diff --git a/brownie/abi/vault_admin.json b/brownie/abi/vault_admin.json index 598774381f..984492e840 100644 --- a/brownie/abi/vault_admin.json +++ b/brownie/abi/vault_admin.json @@ -1 +1 @@ -[ { "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": "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": [ { "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": [], "name": "capitalPaused", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "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": "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": [ { "internalType": "address", "name": "asset", "type": "address" } ], "name": "priceUSDMint", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "asset", "type": "address" } ], "name": "priceUSDRedeem", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "_strategyFromAddress", "type": "address" }, { "internalType": "address", "name": "_strategyToAddress", "type": "address" }, { "internalType": "address[]", "name": "_assets", "type": "address[]" }, { "internalType": "uint256[]", "name": "_amounts", "type": "uint256[]" } ], "name": "reallocate", "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": [], "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": "_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": "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" } ], "name": "supportAsset", "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" }, { "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" } ] \ No newline at end of file +[ { "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": "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": [ { "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": [], "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": [ { "internalType": "address", "name": "asset", "type": "address" } ], "name": "priceUSDMint", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "asset", "type": "address" } ], "name": "priceUSDRedeem", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "_strategyFromAddress", "type": "address" }, { "internalType": "address", "name": "_strategyToAddress", "type": "address" }, { "internalType": "address[]", "name": "_assets", "type": "address[]" }, { "internalType": "uint256[]", "name": "_amounts", "type": "uint256[]" } ], "name": "reallocate", "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": [], "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": "_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": "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" } ], "name": "supportAsset", "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" }, { "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" } ] \ No newline at end of file diff --git a/brownie/metastrategy.py b/brownie/metastrategy.py index 6fc9d596ed..160a79b5fa 100644 --- a/brownie/metastrategy.py +++ b/brownie/metastrategy.py @@ -2,14 +2,6 @@ import world import math -#CONFIGURATION - unfortunately this address changes until we deploy it to mainnet -OUSD_META_STRATEGY = '0xb12C3410C44854054c217fbF79dFf38ffD1C0676' -BUSD_STRATEGY = '0x6996352570817113965b0325005f868B1Fe2f2e9' -# Define which meta strategy should be set as default USDT asset strategy. Important for -# supplying liquidity when minting using USDT -USDT_DEFAULT_META_STRATEGY = OUSD_META_STRATEGY -#USDT_DEFAULT_META_STRATEGY = BUSD_STRATEGY -#END COFIGURATION me = ORIGINTEAM some_gas_price = 100 @@ -30,6 +22,8 @@ DAI_BAGS = '0x40ec5b33f54e0e8a33a975908c5ba1c14e5bbbdf' #polygon bridge DAI_BAGS_2 = '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643' #this is compound cDai. Don't touch this! CURVE_FACTORY = '0xB9fC157394Af804a3578134A6585C0dc9cc990d4' +OUSD_META_STRATEGY = '0x89Eb88fEdc50FC77ae8a18aAD1cA0ac27f777a90' +USDT_DEFAULT_META_STRATEGY = OUSD_META_STRATEGY threepool_lp = load_contract('threepool_lp', THREEPOOL_LP) ousd_metapool = load_contract('ousd_metapool', OUSD_METAPOOL) @@ -52,7 +46,6 @@ frax.transfer(me, frax.balanceOf(FRAX_BAGS), {'from': FRAX_BAGS}) busd.transfer(me, busd.balanceOf(BUSD_BAGS), {'from': BUSD_BAGS}) meta_strat = load_contract('convex_strat', OUSD_META_STRATEGY) -busd_strat = load_contract('convex_strat', BUSD_STRATEGY) # approve ousd and 3poolLp to be used by ousd_metapool threepool_lp.approve(ousd_metapool, int(0), OPTS) diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index 09492ca8a0..1514fa4904 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -113,6 +113,18 @@ interface IVault { uint256[] calldata _amounts ) external; + function withdrawFromStrategy( + address _strategyFromAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) external; + + function depositToStrategy( + address _strategyToAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) external; + // VaultCore.sol function mint( address _asset, diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 0ac7094eb1..bedf84c789 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -233,7 +233,7 @@ contract VaultAdmin is VaultStorage { } /** - * @notice Move assets from one Strategy to another + * @dev Move assets from one Strategy to another * @param _strategyFromAddress Address of Strategy to move assets from. * @param _strategyToAddress Address of Strategy to move assets to. * @param _assets Array of asset address that will be moved @@ -246,27 +246,103 @@ contract VaultAdmin is VaultStorage { uint256[] calldata _amounts ) external onlyGovernorOrStrategist { require( - strategies[_strategyFromAddress].isSupported, - "Invalid from Strategy" + strategies[_strategyToAddress].isSupported, + "Invalid to Strategy" ); + require(_assets.length == _amounts.length, "Parameter length mismatch"); + _withdrawFromStrategy( + _strategyToAddress, + _strategyFromAddress, + _assets, + _amounts + ); + + IStrategy strategyTo = IStrategy(_strategyToAddress); + for (uint256 i = 0; i < _assets.length; i++) { + require(strategyTo.supportsAsset(_assets[i]), "Asset unsupported"); + } + // Tell new Strategy to deposit into protocol + strategyTo.depositAll(); + } + + /** + * @dev Deposit multiple assets from the vault into the strategy. + * @param _strategyToAddress Address of the Strategy to deposit assets into. + * @param _assets Array of asset address that will be deposited into the strategy. + * @param _amounts Array of amounts of each corresponding asset to deposit. + */ + function depositToStrategy( + address _strategyToAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) external onlyGovernorOrStrategist { + _depositToStrategy(_strategyToAddress, _assets, _amounts); + } + + function _depositToStrategy( + address _strategyToAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) internal { require( strategies[_strategyToAddress].isSupported, "Invalid to Strategy" ); require(_assets.length == _amounts.length, "Parameter length mismatch"); - IStrategy strategyFrom = IStrategy(_strategyFromAddress); IStrategy strategyTo = IStrategy(_strategyToAddress); for (uint256 i = 0; i < _assets.length; i++) { require(strategyTo.supportsAsset(_assets[i]), "Asset unsupported"); - // Withdraw from Strategy and pass other Strategy as recipient - strategyFrom.withdraw(address(strategyTo), _assets[i], _amounts[i]); + // Send required amount of funds to the strategy + IERC20(_assets[i]).safeTransfer(_strategyToAddress, _amounts[i]); } - // Tell new Strategy to deposit into protocol + + // Deposit all the funds that have been sent to the strategy strategyTo.depositAll(); } + /** + * @dev Withdraw multiple assets from the strategy to the vault. + * @param _strategyFromAddress Address of the Strategy to withdraw assets from. + * @param _assets Array of asset address that will be withdrawn from the strategy. + * @param _amounts Array of amounts of each corresponding asset to withdraw. + */ + function withdrawFromStrategy( + address _strategyFromAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) external onlyGovernorOrStrategist { + _withdrawFromStrategy( + address(this), + _strategyFromAddress, + _assets, + _amounts + ); + } + + /** + * @param _recipient can either be a strategy or the Vault + */ + function _withdrawFromStrategy( + address _recipient, + address _strategyFromAddress, + address[] calldata _assets, + uint256[] calldata _amounts + ) internal { + require( + strategies[_strategyFromAddress].isSupported, + "Invalid from Strategy" + ); + require(_assets.length == _amounts.length, "Parameter length mismatch"); + + IStrategy strategyFrom = IStrategy(_strategyFromAddress); + for (uint256 i = 0; i < _assets.length; i++) { + // Withdraw from Strategy to the recipient + strategyFrom.withdraw(_recipient, _assets[i], _amounts[i]); + } + } + /** * @dev Sets the maximum allowable difference between * total supply and backing assets' value. diff --git a/contracts/deploy/048_deposit_withdraw_tooling.js b/contracts/deploy/048_deposit_withdraw_tooling.js new file mode 100644 index 0000000000..2c310fe384 --- /dev/null +++ b/contracts/deploy/048_deposit_withdraw_tooling.js @@ -0,0 +1,36 @@ +const { deploymentWithProposal } = require("../utils/deploy"); +const addresses = require("../utils/addresses"); + +module.exports = deploymentWithProposal( + { deployName: "048_deposit_withdraw_tooling", forceDeploy: false }, + async ({ + assetAddresses, + deployWithConfirmation, + ethers, + getTxOpts, + withConfirmation, + }) => { + const { deployerAddr, governorAddr } = await getNamedAccounts(); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + // Current contracts + const cVaultProxy = await ethers.getContract("VaultProxy"); + + const dVaultAdmin = await deployWithConfirmation("VaultAdmin"); + const cVault = await ethers.getContractAt("Vault", cVaultProxy.address); + + // Governance Actions + // ---------------- + return { + name: "Deploy new withdrawal utils", + actions: [ + // 1. Set VaultAdmin implementation + { + contract: cVault, + signature: "setAdminImpl(address)", + args: [dVaultAdmin.address], + }, + ], + }; + } +); diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 492177428c..30a75cbd73 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -167,6 +167,7 @@ async function defaultFixture() { tusd = await ethers.getContractAt(erc20Abi, addresses.mainnet.TUSD); usdc = await ethers.getContractAt(erc20Abi, addresses.mainnet.USDC); cusdt = await ethers.getContractAt(erc20Abi, addresses.mainnet.cUSDT); + cdai = await ethers.getContractAt(erc20Abi, addresses.mainnet.cDAI); cusdc = await ethers.getContractAt(erc20Abi, addresses.mainnet.cUSDC); comp = await ethers.getContractAt(erc20Abi, addresses.mainnet.COMP); crv = await ethers.getContractAt(erc20Abi, addresses.mainnet.CRV); diff --git a/contracts/test/abi/IVault.json b/contracts/test/abi/IVault.json index 16b66e2f53..d27c3f8fdb 100644 --- a/contracts/test/abi/IVault.json +++ b/contracts/test/abi/IVault.json @@ -4,433 +4,313 @@ "sourceName": "contracts/interfaces/IVault.sol", "abi": [ { - "constant": false, - "inputs": [], - "name": "unpauseRebase", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "redeemFeeBps", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "_threshold", "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "AllocateThresholdUpdated", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_strategy", + "type": "address" + }, + { + "indexed": false, "internalType": "uint256", - "name": "_basis", + "name": "_amount", "type": "uint256" } ], - "name": "setTrusteeFeeBps", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "AssetAllocated", + "type": "event" }, { - "constant": true, - "inputs": [], - "name": "governor", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "address", - "name": "", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_strategy", "type": "address" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "AssetDefaultStrategyUpdated", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "_strategyAddr", + "name": "_asset", "type": "address" } ], - "name": "harvest", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "AssetSupported", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [], - "name": "harvestAndSwap", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "CapitalPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "CapitalUnpaused", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "_asset", - "type": "address" - }, - { + "indexed": false, "internalType": "uint256", - "name": "_amount", + "name": "maxSupplyDiff", "type": "uint256" } ], - "name": "transferToken", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "MaxSupplyDiffChanged", + "type": "event" }, { - "constant": true, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "asset", + "name": "_addr", "type": "address" - } - ], - "name": "priceUSDMint", - "outputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "_value", "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "Mint", + "type": "event" }, { - "constant": true, - "inputs": [], - "name": "uniswapAddr", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "address", - "name": "", + "name": "_priceProvider", "type": "address" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "PriceProviderUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "RebasePaused", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "_asset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { + "indexed": false, "internalType": "uint256", - "name": "_minimumOusdAmount", + "name": "_threshold", "type": "uint256" } ], - "name": "mint", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "RebaseThresholdUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "RebaseUnpaused", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", "name": "_addr", "type": "address" - } - ], - "name": "removeStrategy", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "vaultBuffer", - "outputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "_value", "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "Redeem", + "type": "event" }, { - "constant": true, - "inputs": [], - "name": "trusteeFeeBps", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "_redeemFeeBps", "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getAllAssets", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "RedeemFeeUpdated", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", "name": "_address", "type": "address" } ], - "name": "setTrusteeAddress", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getStrategyCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "StrategistUpdated", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "_priceProvider", + "name": "_addr", "type": "address" } ], - "name": "setPriceProvider", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "StrategyApproved", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", "name": "_addr", "type": "address" } ], - "name": "approveStrategy", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "pauseCapital", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "harvest", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "StrategyRemoved", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "_addr", + "name": "_address", "type": "address" } ], - "name": "addSwapToken", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "trusteeAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "TrusteeAddressChanged", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "_asset", - "type": "address" - } - ], - "name": "supportAsset", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "rebaseThreshold", - "outputs": [ - { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "_basis", "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "TrusteeFeeBpsChanged", + "type": "event" }, { - "constant": true, - "inputs": [], - "name": "rebasePaused", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "indexed": false, + "internalType": "uint256", + "name": "_vaultBuffer", + "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "VaultBufferUpdated", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "_strategyAddr", + "name": "_to", "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_yield", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_fee", + "type": "uint256" } ], - "name": "harvestAndSwap", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "YieldDistribution", + "type": "event" }, { - "constant": true, "inputs": [], - "name": "strategistAddr", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", + "name": "allocate", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, "inputs": [ { "internalType": "address", - "name": "_strategyAddr", + "name": "_addr", "type": "address" } ], - "name": "withdrawAllFromStrategy", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "claimGovernance", + "name": "approveStrategy", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, "inputs": [ { "internalType": "address", @@ -438,35 +318,31 @@ "type": "address" } ], - "name": "checkBalance", + "name": "assetDefaultStrategies", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": false, - "inputs": [ + "inputs": [], + "name": "autoAllocateThreshold", + "outputs": [ { "internalType": "uint256", - "name": "_maxSupplyDiff", + "name": "", "type": "uint256" } ], - "name": "setMaxSupplyDiff", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": true, "inputs": [ { "internalType": "uint256", @@ -482,124 +358,77 @@ "type": "uint256[]" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": false, - "inputs": [ + "inputs": [], + "name": "capitalPaused", + "outputs": [ { - "internalType": "uint256", - "name": "_minimumUnitAmount", - "type": "uint256" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "redeemAll", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, "inputs": [ { "internalType": "address", - "name": "_address", + "name": "_asset", "type": "address" } ], - "name": "setStrategistAddr", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, + "name": "checkBalance", + "outputs": [ { "internalType": "uint256", - "name": "_minimumUnitAmount", + "name": "", "type": "uint256" } ], - "name": "redeem", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "_strategyFromAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "_strategyToAddress", - "type": "address" - }, + "inputs": [], + "name": "getAllAssets", + "outputs": [ { "internalType": "address[]", - "name": "_assets", + "name": "", "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "_amounts", - "type": "uint256[]" } ], - "name": "reallocate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, "inputs": [], - "name": "swap", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "internalType": "address", - "name": "asset", - "type": "address" - } - ], - "name": "priceUSDRedeem", + "name": "getAllStrategies", "outputs": [ { - "internalType": "uint256", + "internalType": "address[]", "name": "", - "type": "uint256" + "type": "address[]" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": true, "inputs": [], - "name": "maxSupplyDiff", + "name": "getAssetCount", "outputs": [ { "internalType": "uint256", @@ -607,36 +436,36 @@ "type": "uint256" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": false, - "inputs": [ + "inputs": [], + "name": "getStrategyCount", + "outputs": [ { "internalType": "uint256", - "name": "_vaultBuffer", + "name": "", "type": "uint256" } ], - "name": "setVaultBuffer", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, "inputs": [], - "name": "unpauseCapital", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", "type": "function" }, { - "constant": true, "inputs": [ { "internalType": "address", @@ -652,29 +481,12 @@ "type": "bool" } ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "autoAllocateThreshold", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": true, "inputs": [], - "name": "getAssetCount", + "name": "maxSupplyDiff", "outputs": [ { "internalType": "uint256", @@ -682,81 +494,47 @@ "type": "uint256" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": true, "inputs": [ { "internalType": "address", "name": "_asset", "type": "address" - } - ], - "name": "assetDefaultStrategies", - "outputs": [ + }, { - "internalType": "address", - "name": "", - "type": "address" + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minimumOusdAmount", + "type": "uint256" } ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "allocate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "_address", - "type": "address" - } - ], - "name": "setUniswapAddr", + "name": "mint", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, "inputs": [], - "name": "rebase", + "name": "pauseCapital", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, - "inputs": [ - { - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "setAutoAllocateThreshold", + "inputs": [], + "name": "pauseRebase", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, "inputs": [], "name": "priceProvider", "outputs": [ @@ -766,462 +544,465 @@ "type": "address" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": false, "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "priceUSDMint", + "outputs": [ { "internalType": "uint256", - "name": "_threshold", + "name": "", "type": "uint256" } ], - "name": "setRebaseThreshold", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, "inputs": [ { "internalType": "address", - "name": "_asset", + "name": "asset", "type": "address" - }, + } + ], + "name": "priceUSDRedeem", + "outputs": [ { - "internalType": "address", - "name": "_strategy", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "setAssetDefaultStrategy", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, "inputs": [ { "internalType": "address", - "name": "_addr", + "name": "_strategyFromAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_strategyToAddress", "type": "address" + }, + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" } ], - "name": "removeSwapToken", + "name": "reallocate", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, "inputs": [], - "name": "pauseRebase", + "name": "rebase", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, "inputs": [], - "name": "withdrawAllFromStrategies", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ + "name": "rebasePaused", + "outputs": [ { - "internalType": "address", - "name": "_newGovernor", - "type": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "transferGovernance", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": true, "inputs": [], - "name": "totalValue", + "name": "rebaseThreshold", "outputs": [ { "internalType": "uint256", - "name": "value", + "name": "", "type": "uint256" } ], - "payable": false, "stateMutability": "view", "type": "function" }, { - "constant": true, - "inputs": [], - "name": "capitalPaused", - "outputs": [ + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minimumUnitAmount", + "type": "uint256" } ], - "payable": false, - "stateMutability": "view", + "name": "redeem", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, "inputs": [ { "internalType": "uint256", - "name": "_redeemFeeBps", + "name": "_minimumUnitAmount", "type": "uint256" } ], - "name": "setRedeemFeeBps", + "name": "redeemAll", "outputs": [], - "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, - "inputs": [ - { - "internalType": "address[]", - "name": "_assets", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "_amount", - "type": "uint256[]" - }, + "inputs": [], + "name": "redeemFeeBps", + "outputs": [ { "internalType": "uint256", - "name": "_minimumOusdAmount", + "name": "", "type": "uint256" } ], - "name": "mintMultiple", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "_asset", + "name": "_addr", "type": "address" } ], - "name": "AssetSupported", - "type": "event" + "name": "removeStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", "name": "_asset", "type": "address" }, { - "indexed": false, "internalType": "address", "name": "_strategy", "type": "address" } ], - "name": "AssetDefaultStrategyUpdated", - "type": "event" + "name": "setAssetDefaultStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "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", + "name": "_threshold", "type": "uint256" } ], - "name": "AssetAllocated", - "type": "event" + "name": "setAutoAllocateThreshold", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "_addr", - "type": "address" + "internalType": "uint256", + "name": "_maxSupplyDiff", + "type": "uint256" } ], - "name": "StrategyApproved", - "type": "event" + "name": "setMaxSupplyDiff", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "_addr", + "name": "_priceProvider", "type": "address" } ], - "name": "StrategyRemoved", - "type": "event" + "name": "setPriceProvider", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "_addr", - "type": "address" - }, - { - "indexed": false, "internalType": "uint256", - "name": "_value", + "name": "_threshold", "type": "uint256" } ], - "name": "Mint", - "type": "event" + "name": "setRebaseThreshold", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "_addr", - "type": "address" - }, - { - "indexed": false, "internalType": "uint256", - "name": "_value", + "name": "_redeemFeeBps", "type": "uint256" } ], - "name": "Redeem", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "CapitalPaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "CapitalUnpaused", - "type": "event" + "name": "setRedeemFeeBps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [], - "name": "RebasePaused", - "type": "event" + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setStrategistAddr", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [], - "name": "RebaseUnpaused", - "type": "event" + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setTrusteeAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "uint256", - "name": "_vaultBuffer", + "name": "_basis", "type": "uint256" } ], - "name": "VaultBufferUpdated", - "type": "event" + "name": "setTrusteeFeeBps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "uint256", - "name": "_redeemFeeBps", + "name": "_vaultBuffer", "type": "uint256" } ], - "name": "RedeemFeeUpdated", - "type": "event" + "name": "setVaultBuffer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "strategistAddr", + "outputs": [ { - "indexed": false, "internalType": "address", - "name": "_priceProvider", + "name": "", "type": "address" } ], - "name": "PriceProviderUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" + "internalType": "address", + "name": "_asset", + "type": "address" } ], - "name": "AllocateThresholdUpdated", - "type": "event" + "name": "supportAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "totalValue", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "_threshold", + "name": "value", "type": "uint256" } ], - "name": "RebaseThresholdUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "_address", + "name": "_newGovernor", "type": "address" } ], - "name": "UniswapUpdated", - "type": "event" + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "_address", + "name": "_asset", "type": "address" - } - ], - "name": "StrategistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, { - "indexed": false, "internalType": "uint256", - "name": "maxSupplyDiff", + "name": "_amount", "type": "uint256" } ], - "name": "MaxSupplyDiffChanged", - "type": "event" + "name": "transferToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "trusteeAddress", + "outputs": [ { - "indexed": false, "internalType": "address", - "name": "_to", + "name": "", "type": "address" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trusteeFeeBps", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "_yield", + "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": [ { - "indexed": false, "internalType": "uint256", - "name": "_fee", + "name": "", "type": "uint256" } ], - "name": "YieldDistribution", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "_basis", - "type": "uint256" + "internalType": "address", + "name": "_strategyFromAddress", + "type": "address" + }, + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" } ], - "name": "TrusteeFeeBpsChanged", - "type": "event" + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawAllFromStrategies", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "_address", + "name": "_strategyAddr", "type": "address" } ], - "name": "TrusteeAddressChanged", - "type": "event" + "name": "withdrawAllFromStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ], "bytecode": "0x", diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 8af72071c3..6d855c5d93 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -17,12 +17,21 @@ chai.Assertion.addMethod( "approxEqualTolerance", function (expected, maxTolerancePct = 1, message = undefined) { const actual = this._obj; - chai - .expect(actual, message) - .gte(expected.mul(10000 - maxTolerancePct * 100).div(10000)); - chai - .expect(actual, message) - .lte(expected.mul(10000 + maxTolerancePct * 100).div(10000)); + if (expected.gte(BigNumber.from(0))) { + chai + .expect(actual, message) + .gte(expected.mul(10000 - maxTolerancePct * 100).div(10000)); + chai + .expect(actual, message) + .lte(expected.mul(10000 + maxTolerancePct * 100).div(10000)); + } else { + chai + .expect(actual, message) + .gte(expected.mul(10000 + maxTolerancePct * 100).div(10000)); + chai + .expect(actual, message) + .lte(expected.mul(10000 - maxTolerancePct * 100).div(10000)); + } } ); @@ -117,6 +126,14 @@ function oracleUnits(amount) { return parseUnits(amount, 6); } +function cDaiUnits(amount) { + return parseUnits(amount, 8); +} + +function cUsdcUnits(amount) { + return parseUnits(amount, 8); +} + async function expectApproxSupply(contract, expected, message) { const balance = await contract.totalSupply(); // shortcuts the 0 case, since that's neither gt or lt @@ -395,6 +412,92 @@ async function differenceInErc20TokenBalance(address, tokenContract, asyncFn) { return (await tokenContract.balanceOf(address)).sub(balanceBefore); } +/** + * Return the difference in ERC20 `token` balance of an `address` after + * the `asyncFn` is executed. Takes array as an input and also returns array + * of values + */ +async function differenceInErc20TokenBalances( + addresses, + tokenContracts, + asyncFn +) { + if (addresses.length !== tokenContracts.length) { + throw new Error( + "addresses and tokenContracts arrays need to be of same length" + ); + } + + const arrayLength = addresses.length; + const balancesBefore = Array(arrayLength); + const returnVals = Array(arrayLength); + + for (let i = 0; i < arrayLength; i++) { + balancesBefore[i] = await tokenContracts[i].balanceOf(addresses[i]); + } + await asyncFn(); + + for (let i = 0; i < arrayLength; i++) { + returnVals[i] = (await tokenContracts[i].balanceOf(addresses[i])).sub( + balancesBefore[i] + ); + } + + return returnVals; +} + +/** + * Return the difference strategy balance `strategyContract` for the `assetAddress` asset + * after the `asyncFn` is executed. + * + * assetAddresses & strategyContracts can either be an array or a single address. Return type + * depends on input parameters, can also either be an array or single value + */ +async function differenceInStrategyBalance( + assetAddresses, + strategyContracts, + asyncFn +) { + let inputArray = false; + if (Array.isArray(assetAddresses) || Array.isArray(strategyContracts)) { + inputArray = true; + } else { + // turn into an array for more uniform implementation + assetAddresses = [assetAddresses]; + strategyContracts = [strategyContracts]; + } + + if (assetAddresses.length !== strategyContracts.length) { + throw new Error( + "assetAddresses and strategyContracts arrays need to be of same length" + ); + } + + const arrayLength = assetAddresses.length; + const balancesBefore = Array(arrayLength); + const returnVals = Array(arrayLength); + + for (let i = 0; i < arrayLength; i++) { + balancesBefore[i] = await strategyContracts[i].checkBalance( + assetAddresses[i] + ); + } + await asyncFn(); + + for (let i = 0; i < arrayLength; i++) { + returnVals[i] = ( + await strategyContracts[i].checkBalance(assetAddresses[i]) + ).sub(balancesBefore[i]); + } + + // if input params weren't arrays return a single value + if (!inputArray) { + return returnVals[0]; + } + + return returnVals; +} + async function governorArgs({ contract, signature, args = [] }) { const method = signature.split("(")[0]; const tx = await contract.populateTransaction[method](...args); @@ -450,6 +553,8 @@ module.exports = { ethUnits, fraxUnits, oracleUnits, + cDaiUnits, + cUsdcUnits, units, daiUnitsFormat, ousdUnitsFormat, @@ -481,4 +586,6 @@ module.exports = { changeInBalance, forkOnlyDescribe, differenceInErc20TokenBalance, + differenceInErc20TokenBalances, + differenceInStrategyBalance, }; diff --git a/contracts/test/vault/index.js b/contracts/test/vault/index.js index 0140db7176..c19701d07b 100644 --- a/contracts/test/vault/index.js +++ b/contracts/test/vault/index.js @@ -415,6 +415,152 @@ describe("Vault", function () { ).to.be.revertedWith("Caller is not the Strategist or Governor"); }); + it("Should allow the Governor to call withdraw and then deposit", async () => { + const { vault, governor, dai, josh, compoundStrategy } = await loadFixture( + defaultFixture + ); + + await vault.connect(governor).approveStrategy(compoundStrategy.address); + // Send all DAI to Compound + await vault + .connect(governor) + .setAssetDefaultStrategy(dai.address, compoundStrategy.address); + await dai.connect(josh).approve(vault.address, daiUnits("200")); + await vault.connect(josh).mint(dai.address, daiUnits("200"), 0); + await vault.connect(governor).allocate(); + + await vault + .connect(governor) + .withdrawFromStrategy( + compoundStrategy.address, + [dai.address], + [daiUnits("200")] + ); + + await vault + .connect(governor) + .depositToStrategy( + compoundStrategy.address, + [dai.address], + [daiUnits("200")] + ); + }); + + it("Should allow the Strategist to call withdrawFromStrategy and then depositToStrategy", async () => { + const { vault, governor, dai, josh, strategist, compoundStrategy } = + await loadFixture(defaultFixture); + + await vault.connect(governor).approveStrategy(compoundStrategy.address); + // Send all DAI to Compound + await vault + .connect(governor) + .setAssetDefaultStrategy(dai.address, compoundStrategy.address); + await dai.connect(josh).approve(vault.address, daiUnits("200")); + await vault.connect(josh).mint(dai.address, daiUnits("200"), 0); + await vault.connect(governor).allocate(); + + await vault + .connect(strategist) + .withdrawFromStrategy( + compoundStrategy.address, + [dai.address], + [daiUnits("200")] + ); + + await vault + .connect(strategist) + .depositToStrategy( + compoundStrategy.address, + [dai.address], + [daiUnits("200")] + ); + }); + + it("Should not allow non-Governor and non-Strategist to call withdrawFromStrategy or depositToStrategy", async () => { + const { vault, dai, josh } = await loadFixture(defaultFixture); + + await expect( + vault.connect(josh).withdrawFromStrategy( + vault.address, // Args don't matter because it doesn't reach checks + [dai.address], + [daiUnits("200")] + ) + ).to.be.revertedWith("Caller is not the Strategist or Governor"); + + await expect( + vault.connect(josh).depositToStrategy( + vault.address, // Args don't matter because it doesn't reach checks + [dai.address], + [daiUnits("200")] + ) + ).to.be.revertedWith("Caller is not the Strategist or Governor"); + }); + + it("Should withdrawFromStrategy the correct amount for multiple assests and redeploy them using depositToStrategy", async () => { + const { + vault, + governor, + dai, + usdc, + cusdc, + josh, + strategist, + compoundStrategy, + } = await loadFixture(defaultFixture); + + await vault.connect(governor).approveStrategy(compoundStrategy.address); + // Send all DAI to Compound + await vault + .connect(governor) + .setAssetDefaultStrategy(dai.address, compoundStrategy.address); + + // Add USDC + await compoundStrategy + .connect(governor) + .setPTokenAddress(usdc.address, cusdc.address); + + // Send all USDC to Compound + await vault + .connect(governor) + .setAssetDefaultStrategy(usdc.address, compoundStrategy.address); + + await dai.connect(josh).approve(vault.address, daiUnits("200")); + await vault.connect(josh).mint(dai.address, daiUnits("200"), 0); + await usdc.connect(josh).approve(vault.address, usdcUnits("90")); + await vault.connect(josh).mint(usdc.address, usdcUnits("90"), 0); + await vault.connect(governor).allocate(); + + await vault + .connect(strategist) + .withdrawFromStrategy( + compoundStrategy.address, + [dai.address, usdc.address], + [daiUnits("50"), usdcUnits("90")] + ); + + // correct balances at the end + const expectedVaultDaiBalance = daiUnits("50"); + await expect(await dai.balanceOf(vault.address)).to.equal( + expectedVaultDaiBalance + ); + const expectedVaultUsdcBalance = usdcUnits("90"); + await expect(await usdc.balanceOf(vault.address)).to.equal( + expectedVaultUsdcBalance + ); + + await vault + .connect(strategist) + .depositToStrategy( + compoundStrategy.address, + [dai.address, usdc.address], + [daiUnits("50"), usdcUnits("90")] + ); + + // correct balances after depositing back + await expect(await dai.balanceOf(vault.address)).to.equal(daiUnits("0")); + await expect(await usdc.balanceOf(vault.address)).to.equal(usdcUnits("0")); + }); + it("Should allow Governor and Strategist to set vaultBuffer", async () => { const { vault, governor, strategist } = await loadFixture(defaultFixture); await vault.connect(governor).setVaultBuffer(utils.parseUnits("5", 17)); diff --git a/contracts/test/vault/vault.fork-test.js b/contracts/test/vault/vault.fork-test.js index 0e6d89b4e3..e9ec7e4330 100644 --- a/contracts/test/vault/vault.fork-test.js +++ b/contracts/test/vault/vault.fork-test.js @@ -1,6 +1,6 @@ const { expect } = require("chai"); -const { defaultFixture } = require("./../_fixture"); +const { defaultFixture, impersonateAndFundContract } = require("./../_fixture"); const { utils } = require("ethers"); const { @@ -10,6 +10,8 @@ const { usdtUnits, usdcUnits, daiUnits, + differenceInStrategyBalance, + differenceInErc20TokenBalances, } = require("./../helpers"); /** @@ -152,6 +154,69 @@ forkOnlyDescribe("ForkTest: Vault", function () { expect(balancePreMint).to.approxEqualTolerance(balancePostRedeem, 1); }); + it("should withdraw from and deposit to strategy", async () => { + const { vault, josh, usdc, dai, compoundStrategy } = fixture; + await vault.connect(josh).mint(usdc.address, usdcUnits("90"), 0); + await vault.connect(josh).mint(dai.address, daiUnits("50"), 0); + const strategistSigner = await impersonateAndFundContract( + await vault.strategistAddr() + ); + + let daiBalanceDiff, usdcBalanceDiff, daiStratDiff, usdcStratDiff; + + [daiBalanceDiff, usdcBalanceDiff] = await differenceInErc20TokenBalances( + [vault.address, vault.address], + [dai, usdc], + async () => { + [daiStratDiff, usdcStratDiff] = await differenceInStrategyBalance( + [dai.address, usdc.address], + [compoundStrategy, compoundStrategy], + async () => { + await vault + .connect(strategistSigner) + .depositToStrategy( + compoundStrategy.address, + [dai.address, usdc.address], + [daiUnits("50"), usdcUnits("90")] + ); + } + ); + } + ); + + expect(daiBalanceDiff).to.equal(daiUnits("-50")); + expect(usdcBalanceDiff).to.approxEqualTolerance(usdcUnits("-90"), 1); + + expect(daiStratDiff).gte(daiUnits("50")); + expect(usdcStratDiff).gte(usdcUnits("90")); + + [daiBalanceDiff, usdcBalanceDiff] = await differenceInErc20TokenBalances( + [vault.address, vault.address], + [dai, usdc], + async () => { + [daiStratDiff, usdcStratDiff] = await differenceInStrategyBalance( + [dai.address, usdc.address], + [compoundStrategy, compoundStrategy], + async () => { + await vault + .connect(strategistSigner) + .withdrawFromStrategy( + compoundStrategy.address, + [dai.address, usdc.address], + [daiUnits("50"), usdcUnits("90")] + ); + } + ); + } + ); + + expect(daiBalanceDiff).to.approxEqualTolerance(daiUnits("50"), 1); + expect(usdcBalanceDiff).to.approxEqualTolerance(usdcUnits("90"), 1); + + expect(daiStratDiff).approxEqualTolerance(daiUnits("-50")); + expect(usdcStratDiff).approxEqualTolerance(usdcUnits("-90")); + }); + it("Should have vault buffer disabled", async () => { const { vault } = fixture; expect(await vault.vaultBuffer()).to.equal("0"); @@ -226,7 +291,7 @@ forkOnlyDescribe("ForkTest: Vault", function () { const strategies = await vault.getAllStrategies(); const knownStrategies = [ - // TODO: Update this every time a new strategy is added + // Update this every time a new strategy is added. Below are mainnet addresses "0x9c459eeb3FA179a40329b81C1635525e9A0Ef094", // Compound "0x5e3646A1Db86993f73E6b74A57D8640B69F7e259", // Aave "0xEA2Ef2e2E5A749D4A66b41Db9aD85a38Aa264cb3", // Convex diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index b4c30c3cd7..a882d6b498 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -434,8 +434,16 @@ function deploymentWithProposal(opts, fn) { } main.skip = async () => { + // running on fork with a proposalId already available if (isFork && proposalId) { return false; + /* running on fork, and proposal not yet submitted. This is usually during development + * before kicking off deploy. + */ + } else if (isFork) { + const networkName = isForkTest ? "hardhat" : "localhost"; + const migrations = require(`./../deployments/${networkName}/.migrations.json`); + return Boolean(migrations[deployName]); } else { return !isMainnet || isSmokeTest || isFork; }