diff --git a/abi/AaveVault.json b/abi/AaveVault.json index 8c96918..6eabe03 100644 --- a/abi/AaveVault.json +++ b/abi/AaveVault.json @@ -468,19 +468,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "conversionRateScale", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, { "inputs": [ { diff --git a/abi/Administrator.json b/abi/Administrator.json index 2200a23..efd1db6 100644 --- a/abi/Administrator.json +++ b/abi/Administrator.json @@ -3,28 +3,8 @@ "inputs": [ { "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "internalType": "address", - "name": "maintainer", - "type": "address" - }, - { - "internalType": "address", - "name": "securityCouncil", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolManager", + "name": "initialAdmin", "type": "address" - }, - { - "internalType": "uint32", - "name": "defaultGrantDelay", - "type": "uint32" } ], "stateMutability": "nonpayable", @@ -191,6 +171,11 @@ "name": "FailedCall", "type": "error" }, + { + "inputs": [], + "name": "GovernanceNotAuthorized", + "type": "error" + }, { "inputs": [ { @@ -207,6 +192,11 @@ "name": "InsufficientBalance", "type": "error" }, + { + "inputs": [], + "name": "ProtocolManagerAuthorityMismatch", + "type": "error" + }, { "inputs": [ { @@ -223,6 +213,11 @@ "name": "SafeCastOverflowedUintDowncast", "type": "error" }, + { + "inputs": [], + "name": "VaultAuthorityMismatch", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -1165,6 +1160,49 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin", + "type": "address" + }, + { + "internalType": "address", + "name": "vault", + "type": "address" + }, + { + "internalType": "address", + "name": "maintainer", + "type": "address" + }, + { + "internalType": "address", + "name": "securityCouncil", + "type": "address" + }, + { + "internalType": "address", + "name": "manager", + "type": "address" + }, + { + "internalType": "uint32", + "name": "upgradeDelay", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "adminDelay", + "type": "uint32" + } + ], + "name": "setupGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IProtocolManager.json b/abi/IProtocolManager.json index c218579..31ee267 100644 --- a/abi/IProtocolManager.json +++ b/abi/IProtocolManager.json @@ -80,6 +80,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getMaxDepositFeeBasisPoints", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "pure", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVault.json b/abi/IVault.json index 7c7fc96..76fcd66 100644 --- a/abi/IVault.json +++ b/abi/IVault.json @@ -142,6 +142,24 @@ "name": "Spend", "type": "event" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "paramsHash", + "type": "bytes32" + } + ], + "name": "approveUpgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultErrors.json b/abi/IVaultErrors.json index 45e45a1..d822bd5 100644 --- a/abi/IVaultErrors.json +++ b/abi/IVaultErrors.json @@ -99,5 +99,10 @@ "inputs": [], "name": "InvalidZKProof", "type": "error" + }, + { + "inputs": [], + "name": "ProtocolManagerAuthorityMismatch", + "type": "error" } ] diff --git a/abi/InvestmentVaultLib.json b/abi/InvestmentVaultLib.json index 796848f..e606a25 100644 --- a/abi/InvestmentVaultLib.json +++ b/abi/InvestmentVaultLib.json @@ -14,5 +14,18 @@ ], "name": "SafeERC20FailedOperation", "type": "error" + }, + { + "inputs": [], + "name": "conversionRateScale", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" } ] diff --git a/abi/MockMorphoVault.json b/abi/MockMorphoVault.json new file mode 100644 index 0000000..271f265 --- /dev/null +++ b/abi/MockMorphoVault.json @@ -0,0 +1,832 @@ +[ + { + "inputs": [ + { + "internalType": "contract ERC20", + "name": "asset", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxDeposit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxMint", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxRedeem", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxWithdraw", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "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": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "Deposit", + "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" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "__fakeIncome", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "__fakeLoss", + "outputs": [], + "stateMutability": "nonpayable", + "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": [], + "name": "asset", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "convertToAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "name": "convertToShares", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxRedeem", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "name": "previewDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "previewMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "previewRedeem", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "name": "previewWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "redeem", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/ProtocolManager.json b/abi/ProtocolManager.json index b9743b8..7ed2bf1 100644 --- a/abi/ProtocolManager.json +++ b/abi/ProtocolManager.json @@ -355,6 +355,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getMaxDepositFeeBasisPoints", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "pure", + "type": "function" + }, { "inputs": [ { diff --git a/abi/Vault.json b/abi/Vault.json index bc23919..ee43441 100644 --- a/abi/Vault.json +++ b/abi/Vault.json @@ -195,6 +195,11 @@ "name": "NotInitializing", "type": "error" }, + { + "inputs": [], + "name": "ProtocolManagerAuthorityMismatch", + "type": "error" + }, { "inputs": [], "name": "ReentrancyGuardReentrantCall", @@ -437,6 +442,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "paramsHash", + "type": "bytes32" + } + ], + "name": "approveUpgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -806,12 +829,7 @@ }, { "internalType": "address", - "name": "aavePool", - "type": "address" - }, - { - "internalType": "address", - "name": "aToken", + "name": "strategyVault", "type": "address" } ], @@ -1107,13 +1125,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "upgradeCallBack", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/hardhat.config.ts b/hardhat.config.ts index 4073b95..60bd56d 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -8,8 +8,6 @@ import "hardhat-abi-exporter"; import { mkCreateXSalt } from "./scripts/mkCreateXSalt"; import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; import { existsSync, readFileSync } from "fs"; -import ignitionConfig from "./scripts/ignition.config"; -import { AaveV3Base } from "@aave-dao/aave-address-book"; if (config.error) { console.error(config.error); @@ -52,7 +50,10 @@ export default { salt: mkCreateXSalt(deployerAccounts[0], deploymentSalt), }, }, - config: ignitionConfig, + config: { + blockPollingInterval: 1500, + requiredConfirmations: 2, + }, }, paths: { sources: "src", @@ -72,7 +73,7 @@ export default { "Invoice", "TokenDistributor", "Token", - "AaveVault", + "MockMorphoVault", "Verifiers", ], flat: true, @@ -105,20 +106,6 @@ export default { rnd11Input: deploymentSalt, }, }, - localhostAave: { - url: "http://127.0.0.1:8545", - params: { - admin: config.parsed?.TESTNET_ADMIN_ADDRESS, - maintainer: config.parsed?.TESTNET_MAINTAINER_ADDRESS, - manager: config.parsed?.TESTNET_PROTOCOL_MANAGER_ADDRESS, - securityCouncil: config.parsed?.TESTNET_SECURITY_COUNCIL_ADDRESS, - token: AaveV3Base.ASSETS.USDC.UNDERLYING, - aavePool: AaveV3Base.POOL, - aToken: AaveV3Base.ASSETS.USDC.A_TOKEN, - dropMerkleRoot: loadDropRoot(".local.drop.json"), - rnd11Input: deploymentSalt, - }, - }, baseSepolia: { url: config.parsed?.BASE_SEPOLIA_RPC ?? mockRpc, accounts: deployerAccounts, @@ -139,9 +126,8 @@ export default { maintainer: config.parsed?.MAINTAINER_ADDRESS, manager: config.parsed?.PROTOCOL_MANAGER_ADDRESS, securityCouncil: config.parsed?.SECURITY_COUNCIL_ADDRESS, - token: AaveV3Base.ASSETS.USDC.UNDERLYING, - aavePool: AaveV3Base.POOL, - aToken: AaveV3Base.ASSETS.USDC.A_TOKEN, + token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + strategyVault: "0x9b939BE68658998efD2aA2589E34f1b49D6b0C5f", dropMerkleRoot: loadDropRoot(".drop.json"), donor: config.parsed?.DONOR_ADDRESS, rnd11Input: deploymentSalt, diff --git a/ignition/deployments/chain-84532/deployed_addresses.json b/ignition/deployments/chain-84532/deployed_addresses.json index 1698572..a3bcfb5 100644 --- a/ignition/deployments/chain-84532/deployed_addresses.json +++ b/ignition/deployments/chain-84532/deployed_addresses.json @@ -1,34 +1,33 @@ { - "Mocks#MockERC20": "0xdBe053fbAd4461F48bB01FF5AD839720Daa95Ed0", - "Mocks#MockAavePool": "0x9703D4B93c2ec33bf2bAFaB4Dd629F68e08b58F1", - "Main#DepositVerifier": "0x55FB64D85EaFA82E8F32865D2e69F715a0bbe0B7", - "Main#Spend11Verifier": "0x8B5EFAfcb958397b37C63854Db171117Ce4447B2", - "Main#Spend12Verifier": "0x11f757882bDCaa6A9CE6b47581D9778b5aEC44DF", - "Main#Spend13Verifier": "0x38212D7818EFD3F8BcfC6B7d1EfaEE164a09a58c", - "Main#Spend21Verifier": "0x55451dd5eE47b3b3C29da1eD58bD9844d0DCbb92", - "Main#Spend22Verifier": "0xe50714003f5C346Cb54F591A9A7aF5091Ac13996", - "Main#Spend23Verifier": "0xA5eD9981d675DeFe33874e12956581CC0A91d549", - "Main#Spend31Verifier": "0xDc85f45674C4cb8F050EA65A0e1Afc13676E8c65", - "Main#Spend32Verifier": "0xD592BD3AEe488b001B824e71401Ef164BEd29Bf8", - "Main#Spend33Verifier": "0x8CAe74aE9447172768e5FF1055F5197B81f332D4", - "Main#Spend61Verifier": "0xFa151B788E8086889C84908712e7874331350dAc", - "Main#Spend121Verifier": "0x5df418f0899d89D94D33C29C8B888ab5CAa5D0d6", - "Main#Verifiers": "0x8cB16a8b56eA9984C45E2D130e0b5281a329b206", - "Main#Administrator_0": "0x01a9D91D24DF24DE4d90c34c0aa29784d8321FF1", - "Main#Forwarder_0": "0x8a0C90856C1A81a2b9BF4Adf921bc8B2828D9CC7", - "Main#InvoiceFactory_0": "0xB0E13277b03C02A9D427224fa5792a9a7786deBd", - "Main#TokenDistributorDeployLib_0": "0x561658FedFCcA646b50Dd3fc4e0ADA16375BD9B1", - "Main#InterestLib_0": "0x07522E3F1DdC99F314b7c3f9dFe85CD2fCA4A2BA", - "Main#VaultMathLib_0": "0xD4e401DBB21ec9A98F4e34024A648e35f09038BE", - "Main#InputsLib_0": "0x62E508EA530b1607b21c3C1A6D8357Ba2A41b555", - "Main#InvestmentVaultLib_0": "0xedc074D61A6076EEC3A8a98F6ce31C6297526579", - "Main#AaveVaultDeployerLib_0": "0x6C267363589143FD92C154CB5646a3A3Ca9fb3F2", - "Main#InputModifierLib_0": "0x2E840aC1134C57ce82d826F4509aFD13260b8B8C", - "Main#VaultInitLib_0": "0x60A25A821ce0e6C9383d9d48ed333D7b1C2742ce", - "Main#VaultDepositLib_0": "0x69b0f294be322a77e5BDf1Bc2f6e234b7fA4Cae2", - "Main#VaultSpendLib_0": "0xE64687D85ddb946034b42c6052CF117Fe5f100Df", - "Main#Vault_0": "0x35480d185866D0DF92fb49131644D510c5eDdaD5", - "Main#VaultProxy": "0xc0a2e7E64E0042041c2E4D3510B439a05D517609", - "Main#Vault": "0xc0a2e7E64E0042041c2E4D3510B439a05D517609", - "Main#ProtocolManager": "0x7546E6B2e639F39050f5CF031785B7088Bf9e780" + "Mocks#MockERC20": "0x5755ffa8B8E369bf765e9dD19CdB839f3C803a4C", + "Mocks#MockMorphoVault": "0x8E1Ff380e302A56185F867857cC5F808F1fF253b", + "Main#DepositVerifier": "0xb04a2f3E311a20eE75c9E1b52a709AA604168ac8", + "Main#Spend11Verifier": "0xD6E9ecf3d1F7212dDD2D5D3368C5fEC47eD1a6aD", + "Main#Spend12Verifier": "0x94385E56d0914A391622877cB2f582cc0562844F", + "Main#Spend13Verifier": "0xF6FD9199B4d97664B4Ac37B248C5CfF6F0673B18", + "Main#Spend21Verifier": "0xa77e5809749de4C05C324b4F01Ae4D47585b555C", + "Main#Spend22Verifier": "0x4825D94365f01b447AB62C0C4fe5450E076ff6AD", + "Main#Spend23Verifier": "0xdd60ed1328b0575C6a835e832Fa8e7042FCd0621", + "Main#Spend31Verifier": "0x31Af179160AD9Ca477Ed0D00508449A06D37F4C7", + "Main#Spend32Verifier": "0x8fEb0dcfe925BA77e099D81b849c36D8f0D50BeF", + "Main#Spend33Verifier": "0x3Fc4c1692F9392FBeC9AC185657e7d23187b0724", + "Main#Spend61Verifier": "0xACd322b471323D658Bdc3124eAd02C87802E9f00", + "Main#Spend121Verifier": "0x7379873357fA51437F435703E510D1473B493203", + "Main#Verifiers": "0x3247B4889031780d4Af1F1024928fF1689fc684C", + "Main#Administrator_0": "0xbc7Ecc662137FfBD3e1c9fF29Eae01752c262C96", + "Main#Forwarder_0": "0x975586Cd582Ed0c0798fc5cc3835c42899317f46", + "Main#InvoiceFactory_0": "0xE07Ee6C9810F6a8cD0cf163E3edB154cd7bC454f", + "Main#TokenDistributorDeployLib_0": "0xfdC50ba7162aB834a05E321d36d4D345fa013d25", + "Main#InterestLib_0": "0x6b496dC11f4F0312A03dE99C0E09B01f84514cCF", + "Main#VaultMathLib_0": "0x946907aE0c520160032C97E1007A6B915fa8fbfe", + "Main#InputsLib_0": "0x70db9D60042868367378232feC409787576428E3", + "Main#InvestmentVaultLib_0": "0xb9B2A603a82890BCA29b54a7AC45910b1a8a4988", + "Main#InputModifierLib_0": "0x7C9804729ca3a08DaD65Dfb920862BF9434911B5", + "Main#VaultInitLib_0": "0x227a35631DdE2A77C7c4Ee1942aBaD5b4336a4Bf", + "Main#VaultDepositLib_0": "0x8048322B45180bed0a5Db7339b58ef2dc265ab44", + "Main#VaultSpendLib_0": "0x6C5352AE27CC4eBaDa885904a8830335E73595C0", + "Main#Vault_0": "0x7F2be8302c846987017e8417DE9261c8bfc7e624", + "Main#VaultProxy": "0x1E0eBc83A62319095082373fc82C11c5786f6FdA", + "Main#Vault": "0x1E0eBc83A62319095082373fc82C11c5786f6FdA", + "Main#ProtocolManager": "0x8b6455A66B03B9BfA9Dc87Bd5B80a3AB4053DdA2" } diff --git a/ignition/modules/Main.module.ts b/ignition/modules/Main.module.ts index 35d03a5..da3671d 100644 --- a/ignition/modules/Main.module.ts +++ b/ignition/modules/Main.module.ts @@ -66,22 +66,17 @@ export default buildModule("Main", (m) => { id: `InvestmentVaultLib_${process.env.VERSION_TAG ?? 0}`, after: [inputsLib], }); - const aaveVaultDeployerLib = m.library("AaveVaultDeployerLib", { - id: `AaveVaultDeployerLib_${process.env.VERSION_TAG ?? 0}`, - after: [investmentVaultLib], - }); const inputModifierLib = m.library("InputModifierLib", { id: `InputModifierLib_${process.env.VERSION_TAG ?? 0}`, libraries: { VaultMathLib: vaultMathLib, InterestLib: interestLib, InvestmentVaultLib: investmentVaultLib }, - after: [aaveVaultDeployerLib], + after: [investmentVaultLib], }); const vaultInitLib = m.library("VaultInitLib", { id: `VaultInitLib_${process.env.VERSION_TAG ?? 0}`, libraries: { TokenDistributorDeployLib: tokenDistributorDeployLib, - AaveVaultDeployerLib: aaveVaultDeployerLib, InvestmentVaultLib: investmentVaultLib, }, after: [inputModifierLib], @@ -122,8 +117,7 @@ export default buildModule("Main", (m) => { }); const token = m.getParameter("token"); - const aavePool = m.getParameter("aavePool"); - const aToken = m.getParameter("aToken"); + const strategyVault = m.getParameter("strategyVault"); const dropMerkleRoot = m.getParameter( "dropMerkleRoot", @@ -153,7 +147,7 @@ export default buildModule("Main", (m) => { const contractInitialize = m.call( vault, "initialize", - [verifiers, forwarder, protocolManager, administrator, dropMerkleRoot, token, aavePool, aToken], + [verifiers, forwarder, protocolManager, administrator, dropMerkleRoot, token, strategyVault], { after: [protocolManager] }, ); @@ -182,7 +176,6 @@ export default buildModule("Main", (m) => { inputsLib, vaultMathLib, investmentVaultLib, - aaveVaultDeployerLib, invoiceFactory, }; }); diff --git a/ignition/modules/Mocks.module.ts b/ignition/modules/Mocks.module.ts index 09b35e6..fb08e20 100644 --- a/ignition/modules/Mocks.module.ts +++ b/ignition/modules/Mocks.module.ts @@ -3,10 +3,10 @@ import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; export default buildModule("Mocks", (m) => { const mockERC20 = m.contract("MockERC20", ["MockUSDZ", "USDZ0"]); const mintFeature = m.call(mockERC20, "mint", [m.getParameter("admin"), 1_000_000n * 10n ** 6n]); - const mockAavePool = m.contract("MockAavePool", [mockERC20], { after: [mintFeature] }); + const mockMorphoVault = m.contract("MockMorphoVault", [mockERC20], { after: [mintFeature] }); return { mockERC20, - mockAavePool, + mockMorphoVault, }; }); diff --git a/integration/vault/vault.test.ts b/integration/vault/vault.test.ts index 6c7487b..1f1b2a7 100644 --- a/integration/vault/vault.test.ts +++ b/integration/vault/vault.test.ts @@ -1,5 +1,4 @@ import { expect } from "chai"; -import { ethers } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { deployVaultFixture, @@ -19,13 +18,13 @@ async function getFirstFactor(vault: Vault, tokenAddress: string, hashes: string return (await vault.previewFactors(tokenAddress, hashes))[0]; } -describe("Vault lifecycle (Aave mock + ZK spend_11)", function () { +describe("Vault lifecycle (Morpho mock + ZK spend_11)", function () { it("deposits > yield > transfer > loss", async function () { const { vault, verifiers, mockToken, - mockAavePool, + mockMorphoVault, owner, user: userA, otherUser: userB, @@ -34,9 +33,8 @@ describe("Vault lifecycle (Aave mock + ZK spend_11)", function () { } = await loadFixture(deployVaultFixture); const tokenAddress = await mockToken.getAddress(); const strategyAddress = await vault.getInvestmentStrategyVault(tokenAddress); - const strategy = await ethers.getContractAt("AaveVault", strategyAddress); - const aTokenAddress = await mockAavePool.aToken(); - const aToken = await ethers.getContractAt("MockAToken", aTokenAddress); + const strategy = mockMorphoVault; + expect(strategyAddress).to.equal(await mockMorphoVault.getAddress()); const vaultAddress = await vault.getAddress(); const decimalsPow = 10n ** BigInt(await mockToken.decimals()); @@ -60,7 +58,7 @@ describe("Vault lifecycle (Aave mock + ZK spend_11)", function () { expect(await mockToken.balanceOf(forwarderFeeRecipient)).to.equal(0n); expect(await mockToken.balanceOf(vaultAddress)).to.equal(0n); expect(await vault.getCuratorPerformanceFeeToCollect(tokenAddress)).to.equal(0n); - expect(await aToken.balanceOf(strategy)).to.equal(0n); + expect(await strategy.totalAssets()).to.equal(0n); const { commitmentData: aCommit } = await deposit( userA, @@ -75,7 +73,6 @@ describe("Vault lifecycle (Aave mock + ZK spend_11)", function () { expect(await mockToken.balanceOf(forwarderFeeRecipient)).to.equal(two); expect(await mockToken.balanceOf(vaultAddress)).to.equal(ten); expect(await vault.getCuratorPerformanceFeeToCollect(tokenAddress)).to.equal(0n); - expect(await aToken.balanceOf(strategy)).to.equal(hundred - two - ten); expect(await strategy.totalAssets()).to.equal(hundred - two - ten); expect(await getFirstFactor(vault, tokenAddress, aCommit.hashes)).to.equal(1010309278n); @@ -95,13 +92,12 @@ describe("Vault lifecycle (Aave mock + ZK spend_11)", function () { expect(await mockToken.balanceOf(forwarderFeeRecipient)).to.equal(two + two); expect(await mockToken.balanceOf(vaultAddress)).to.equal(ten); expect(await vault.getCuratorPerformanceFeeToCollect(tokenAddress)).to.equal(0n); - expect(await aToken.balanceOf(strategy)).to.equal((hundred - two) * 2n - ten); expect(strategyBalanceBeforeYield).to.equal((hundred - two) * 2n - ten); expect(await getFirstFactor(vault, tokenAddress, aCommit.hashes)).to.equal(1020618556n); expect(await getFirstFactor(vault, tokenAddress, bCommit.hashes)).to.equal(INPUTS_MODIFIER_SCALE); const income = strategyBalanceBeforeYield / 10n; - await mockAavePool.__fakeIncome(strategy, income); + await strategy.__fakeIncome(income); const factorA = await getFirstFactor(vault, tokenAddress, aCommit.hashes); expect(factorA).to.equal(1107787713n); @@ -167,7 +163,7 @@ describe("Vault lifecycle (Aave mock + ZK spend_11)", function () { expect(factorA2).to.equal(1118406164n); const strategyBalanceSnapshot = await strategy.totalAssets(); const loss = strategyBalanceSnapshot / 2n; - await mockAavePool.__fakeLoss(strategy, loss); + await strategy.__fakeLoss(loss); const strategyBalanceAfterLoss = await strategy.totalAssets(); expect(strategyBalanceAfterLoss).to.equal(strategyBalanceSnapshot - loss); expect(await getFirstFactor(vault, tokenAddress, aCommit.hashes)).to.equal(580650244n); diff --git a/integration/vault/vault.test.utils.ts b/integration/vault/vault.test.utils.ts index 37da86d..d602210 100644 --- a/integration/vault/vault.test.utils.ts +++ b/integration/vault/vault.test.utils.ts @@ -12,7 +12,7 @@ import { InvoiceFactory, ProtocolManager, MockERC20, - MockAavePool, + MockMorphoVault, } from "../../typechain-types"; import MainModule from "../../ignition/modules/Main.module"; import MocksModule from "../../ignition/modules/Mocks.module"; @@ -50,12 +50,12 @@ export interface DepositProofData { export interface TestFixture { vault: Vault; mockToken: MockERC20; - mockAavePool: MockAavePool; + mockMorphoVault: MockMorphoVault; verifiers: Verifiers; owner: HardhatEthersSigner; user: HardhatEthersSigner; otherUser: HardhatEthersSigner; - forwarder: Forwarder; // Add zeroLedgerForwarder for meta-tx tests + forwarder: Forwarder; protocolManager: ProtocolManager; invoiceFactory: InvoiceFactory; forwarderFeeRecipient: string; @@ -94,7 +94,7 @@ export const mockMetadata = randomBytes(32); export async function deployVaultFixture(): Promise { const [owner, user, otherUser, forwarderFeeRecipient] = await ethers.getSigners(); - const { mockERC20, mockAavePool } = await ignition.deploy(MocksModule, { + const { mockERC20, mockMorphoVault } = await ignition.deploy(MocksModule, { parameters: { Mocks: { admin: owner.address, @@ -102,10 +102,9 @@ export async function deployVaultFixture(): Promise { }, }); - const [tokenAddress, aavePoolAddress, aTokenAddress] = await Promise.all([ + const [tokenAddress, morphoVaultAddress] = await Promise.all([ mockERC20.getAddress(), - mockAavePool.getAddress(), - mockAavePool.aToken(), + mockMorphoVault.getAddress(), ]); // ProtocolManager caps spend fee at ceil(totalSupply / 100_000); mint before deploy so constructor passes. @@ -130,8 +129,7 @@ export async function deployVaultFixture(): Promise { curatorPerformanceFee: 0n, investmentStrategyAssetsOffset: 0n, token: tokenAddress, - aavePool: aavePoolAddress, - aToken: aTokenAddress, + strategyVault: morphoVaultAddress, }, }, }, @@ -147,7 +145,7 @@ export async function deployVaultFixture(): Promise { return { vault: vault as unknown as Vault, mockToken: mockERC20 as unknown as MockERC20, - mockAavePool: mockAavePool as unknown as MockAavePool, + mockMorphoVault: mockMorphoVault as unknown as MockMorphoVault, verifiers: verifiers as unknown as Verifiers, owner, user, diff --git a/package.json b/package.json index 3b899be..64fa789 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "deploy:upgrade": "rm -rf ignition/deployments/chain-31337; hardhat run scripts/deployVaultUpgrade.ts --network", "encodeUpgradeCallBack": "hardhat run scripts/encodeUpgradeCallBack.ts", "balances": "hardhat run scripts/prepareBalances.ts --network localhostAave", - "income": "hardhat run scripts/emulateAaveIncome.ts --network", - "loss": "hardhat run scripts/emulateAaveLoss.ts --network", + "income": "hardhat run scripts/emulateLendingIncome.ts --network", + "loss": "hardhat run scripts/emulateLendingLoss.ts --network", "abi": "hardhat export-abi", "prepare": "husky" }, @@ -31,7 +31,6 @@ "url": "https://github.com:zeroledger/contracts/issues" }, "dependencies": { - "@aave-dao/aave-address-book": "^4.48.1", "@openzeppelin/contracts": "^5.4.0", "@openzeppelin/contracts-upgradeable": "^5.4.0", "solady": "^0.1.26" diff --git a/scripts/deploy.ts b/scripts/deploy.ts index f5d8584..eee917d 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -3,7 +3,6 @@ import MainModule from "../ignition/modules/Main.module"; import { NetworkConfig } from "hardhat/types"; import { mkCreateXSalt } from "./mkCreateXSalt"; import MocksModule from "../ignition/modules/Mocks.module"; -import ignitionConfig from "./ignition.config"; import { deploymentChange } from "./deploymentChange"; type Params = { @@ -12,8 +11,7 @@ type Params = { manager?: string; securityCouncil: string; token?: string; - aavePool?: string; - aToken?: string; + strategyVault?: string; dropMerkleRoot?: string; rnd11Input?: string; donor?: string; @@ -30,6 +28,29 @@ async function main() { console.log(`Deployer: ${deployer.address}`); const isHardhat = hre.network.name === "hardhat"; + let ignitionConfig; + + switch (hre.network.name) { + case "hardhat": + ignitionConfig = { + blockPollingInterval: 1500, + requiredConfirmations: 2, + }; + break; + case "localhost": + ignitionConfig = { + blockPollingInterval: 1500, + requiredConfirmations: 3, + }; + break; + default: + ignitionConfig = { + blockPollingInterval: 1900, + requiredConfirmations: 15, + }; + break; + } + const rawParams = ( hre.network.config as NetworkConfig & { params?: Params; @@ -49,12 +70,11 @@ async function main() { const salt = mkCreateXSalt(deployer.address, params.rnd11Input!); let token = params.token; - let aavePool = params.aavePool; - let aToken = params.aToken; + let strategyVault = params.strategyVault; - if (!params.token || !params.aavePool || !params.aToken) { + if (!params.token || !params.strategyVault) { console.log(`Deploying mocks with salt: ${salt}`); - const { mockERC20, mockAavePool } = await hre.ignition.deploy(MocksModule, { + const { mockERC20, mockMorphoVault } = await hre.ignition.deploy(MocksModule, { strategy: isHardhat ? "basic" : "create2", parameters: { Mocks: { @@ -69,17 +89,15 @@ async function main() { console.log(`Mocks deployed. Reading addresses...`); - const [mockERC20Address, mockAavePoolAddress, aTokenAddress] = await Promise.all([ + const [mockERC20Address, mockMorphoVaultAddress] = await Promise.all([ mockERC20.getAddress(), - mockAavePool.getAddress(), - mockAavePool.aToken(), + mockMorphoVault.getAddress(), ]); await new Promise((resolve) => setTimeout(() => resolve(), 2_000)); token = mockERC20Address; - aavePool = mockAavePoolAddress; - aToken = aTokenAddress; + strategyVault = mockMorphoVaultAddress; } const dropMerkleRoot = params.dropMerkleRoot ?? "0x0000000000000000000000000000000000000000000000000000000000000000"; @@ -90,8 +108,7 @@ async function main() { manager: ${manager} securityCouncil: ${securityCouncil} token: ${token} - aavePool: ${aavePool} - aToken: ${aToken} + strategyVault: ${strategyVault} salt: ${salt} dropMerkleRoot: ${dropMerkleRoot} `); @@ -118,8 +135,7 @@ async function main() { curatorPerformanceFee, investmentStrategyAssetsOffset, token: token!, - aavePool: aavePool!, - aToken: aToken!, + strategyVault: strategyVault!, dropMerkleRoot, admin, maintainer, @@ -155,8 +171,7 @@ async function main() { console.log(`Contracts deployed. Addresses: token: ${token} - aToken: ${aToken} - aavePool: ${aavePool} + strategyVault: ${strategyVault} verifiers: ${verifiersAddress} forwarder: ${forwarderAddress} -------------------------- diff --git a/scripts/emulateAaveIncome.ts b/scripts/emulateAaveIncome.ts deleted file mode 100644 index c858e74..0000000 --- a/scripts/emulateAaveIncome.ts +++ /dev/null @@ -1,16 +0,0 @@ -import hre from "hardhat"; - -async function main() { - const pool = await hre.ethers.getContractAt("MockAavePool", process.env.MOCK_AAVE_POOL_ADDRESS!); - const aToken = await hre.ethers.getContractAt("MockAToken", await pool.aToken()); - const vault = await hre.ethers.getContractAt("Vault", process.env.VAULT_ADDRESS!); - await pool.__fakeIncome( - await vault.getInvestmentStrategyVault(await pool.asset()), - hre.ethers.parseUnits("0.05", await aToken.decimals()), - ); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/emulateAaveLoss.ts b/scripts/emulateAaveLoss.ts deleted file mode 100644 index 0884157..0000000 --- a/scripts/emulateAaveLoss.ts +++ /dev/null @@ -1,16 +0,0 @@ -import hre from "hardhat"; - -async function main() { - const pool = await hre.ethers.getContractAt("MockAavePool", process.env.MOCK_AAVE_POOL_ADDRESS!); - const aToken = await hre.ethers.getContractAt("MockAToken", await pool.aToken()); - const vault = await hre.ethers.getContractAt("Vault", process.env.VAULT_ADDRESS!); - await pool.__fakeLoss( - await vault.getInvestmentStrategyVault(await pool.asset()), - hre.ethers.parseUnits("5", await aToken.decimals()), - ); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); \ No newline at end of file diff --git a/scripts/emulateLendingIncome.ts b/scripts/emulateLendingIncome.ts new file mode 100644 index 0000000..f120002 --- /dev/null +++ b/scripts/emulateLendingIncome.ts @@ -0,0 +1,12 @@ +import hre from "hardhat"; + +async function main() { + const pool = await hre.ethers.getContractAt("MockMorphoVault", process.env.MOCK_MORPHO_VAULT_ADDRESS!); + const token = await hre.ethers.getContractAt("MockERC20", await pool.asset()); + await pool.__fakeIncome(hre.ethers.parseUnits("0.5", await token.decimals())); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/emulateLendingLoss.ts b/scripts/emulateLendingLoss.ts new file mode 100644 index 0000000..58aeb99 --- /dev/null +++ b/scripts/emulateLendingLoss.ts @@ -0,0 +1,12 @@ +import hre from "hardhat"; + +async function main() { + const pool = await hre.ethers.getContractAt("MockMorphoVault", process.env.MOCK_MORPHO_VAULT_ADDRESS!); + const token = await hre.ethers.getContractAt("MockERC20", await pool.asset()); + await pool.__fakeLoss(hre.ethers.parseUnits("0.5", await token.decimals())); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/ignition.config.ts b/scripts/ignition.config.ts deleted file mode 100644 index 6bea2dd..0000000 --- a/scripts/ignition.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default { - blockPollingInterval: 1500, - requiredConfirmations: 3, -}; diff --git a/src/Strategy.types.sol b/src/Strategy.types.sol deleted file mode 100644 index 6f2b67c..0000000 --- a/src/Strategy.types.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.21; - -import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; - -/** - * @title Strategy - * @notice Interface for the strategy. - * @author ZeroLedger - */ -interface IStrategy { - /// @notice The scale for the conversion rate. - /// @return conversionRateScale The scale for the conversion rate. - function conversionRateScale() external pure returns (uint256); -} - -interface IERC4626Strategy is IERC4626, IStrategy {} diff --git a/src/aave/AaveVault.sol b/src/aave/AaveVault.sol index 5bec9ac..d88f5b0 100644 --- a/src/aave/AaveVault.sol +++ b/src/aave/AaveVault.sol @@ -6,7 +6,6 @@ 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 {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {IStrategy} from "src/Strategy.types.sol"; /** * @title IAavePool @@ -38,7 +37,7 @@ interface IAavePool { * @notice A ERC-4626 vault that invest ERC20 tokens into Aave protocol * @author ZeroLedger */ -contract AaveVault is IStrategy, ERC4626, Ownable { +contract AaveVault is ERC4626, Ownable { using SafeERC20 for IERC20; /// @notice Aave v3 pool used for supply and withdraw operations. @@ -46,8 +45,6 @@ contract AaveVault is IStrategy, ERC4626, Ownable { /// @notice aToken paired with the underlying vault asset. IERC20 public immutable aToken; - uint256 internal constant _CONVERSION_RATE_SCALE = 1e9; - /** * @notice Creates an ERC4626 vault that routes underlying to Aave. * @param pool_ Address of Aave v3 pool. @@ -68,11 +65,6 @@ contract AaveVault is IStrategy, ERC4626, Ownable { asset_.forceApprove(pool_, type(uint256).max); } - /// @inheritdoc IStrategy - function conversionRateScale() public pure returns (uint256) { - return _CONVERSION_RATE_SCALE; - } - /// @inheritdoc ERC4626 function totalAssets() public view override returns (uint256) { return aToken.balanceOf(address(this)); diff --git a/src/helpers/MockMorphoVault.sol b/src/helpers/MockMorphoVault.sol new file mode 100644 index 0000000..6375467 --- /dev/null +++ b/src/helpers/MockMorphoVault.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.21; + +import {ERC4626, ERC20} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; +import {MockERC20} from "./MockERC20.sol"; + +contract MockMorphoVault is ERC4626 { + constructor( + ERC20 asset + ) ERC4626(asset) ERC20(string.concat("Morpho_", asset.name()), string.concat("Morpho_", asset.symbol())) {} + + /// @notice Simulates yield: mints tokens to the vault + function __fakeIncome(uint256 amount) external { + MockERC20(asset()).mint(address(this), amount); + } + + /// @notice Simulates loss by burning tokens from the vault + function __fakeLoss(uint256 amount) external { + MockERC20(asset()).burn(amount); + } + + // -- Morpho V2 returns 0 for all max* view functions ----------------------- + + function maxWithdraw(address) public pure override returns (uint256) { + return 0; + } + + function maxMint(address) public pure override returns (uint256) { + return 0; + } + + function maxDeposit(address) public pure override returns (uint256) { + return 0; + } + + function maxRedeem(address) public pure override returns (uint256) { + return 0; + } + + // -- Morpho V2 overrides entry points to bypass the max* gates ------------- + + function deposit(uint256 assets, address receiver) public override returns (uint256) { + uint256 shares = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, shares); + return shares; + } + + function mint(uint256 shares, address receiver) public override returns (uint256) { + uint256 assets = previewMint(shares); + _deposit(_msgSender(), receiver, assets, shares); + return assets; + } + + function withdraw(uint256 assets, address receiver, address owner) public override returns (uint256) { + uint256 shares = previewWithdraw(assets); + _withdraw(_msgSender(), receiver, owner, assets, shares); + return shares; + } + + function redeem(uint256 shares, address receiver, address owner) public override returns (uint256) { + uint256 assets = previewRedeem(shares); + _withdraw(_msgSender(), receiver, owner, assets, shares); + return assets; + } +} diff --git a/src/invoice/Invoice.sol b/src/invoice/Invoice.sol index 1d7afa1..dc56a29 100644 --- a/src/invoice/Invoice.sol +++ b/src/invoice/Invoice.sol @@ -88,25 +88,17 @@ contract Invoice is Initializable { ) external { InvoiceState storage $ = _getStorage(); bytes32 computedParamsHash = InvoiceLib.computeParamsHash( - vault, - token, - amount, - executionFee, - commitmentParams, - priorityDeadline, - primaryExecutor + vault, token, amount, executionFee, commitmentParams, priorityDeadline, primaryExecutor ); require(computedParamsHash == $.paramsHash, "Invoice: Invalid params hash"); IERC20(token).forceApprove(vault, amount); if (block.timestamp < priorityDeadline) { IVault(vault).deposit( - DepositParams(token, amount, commitmentParams, protocolFee, executionFee, primaryExecutor, false), - proof + DepositParams(token, amount, commitmentParams, protocolFee, executionFee, primaryExecutor, false), proof ); } else { IVault(vault).deposit( - DepositParams(token, amount, commitmentParams, protocolFee, executionFee, executor, false), - proof + DepositParams(token, amount, commitmentParams, protocolFee, executionFee, executor, false), proof ); } diff --git a/src/vault/InvestmentVault.lib.sol b/src/vault/InvestmentVault.lib.sol index 07221e7..0ada127 100644 --- a/src/vault/InvestmentVault.lib.sol +++ b/src/vault/InvestmentVault.lib.sol @@ -2,14 +2,14 @@ pragma solidity >=0.8.21; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC4626Strategy} from "src/Strategy.types.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {State} from "src/vault/VaultStorage.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; /** - * @title InvestmentVault - * @notice A library for zeroldger investment vault management + * @title InvestmentVaultLib + * @notice A library for zeroldger investment vault v2 management * @author ZeroLedger */ library InvestmentVaultLib { @@ -17,6 +17,12 @@ library InvestmentVaultLib { error InsufficientWithdrawLiquidity(); + /// @notice The scale for the conversion rate. + /// @return conversionRateScale The scale for the conversion rate. + function conversionRateScale() public pure returns (uint256) { + return 1e9; + } + /** * @notice Computes the gain/loss delta for the strategy based on price-per-share snapshots. * @param state The state of the vault. @@ -50,10 +56,9 @@ library InvestmentVaultLib { view returns (uint208, bool, uint208, uint208) { - IERC4626Strategy strategy = IERC4626Strategy(state.investmentStrategyVault[token]); + IERC4626 strategy = IERC4626(state.investmentStrategyVault[token]); uint256 shares = strategy.balanceOf(address(this)); - uint256 conversionRateScale = strategy.conversionRateScale(); - uint208 ppsNow = uint208(strategy.convertToAssets(conversionRateScale)); + uint208 ppsNow = uint208(strategy.convertToAssets(conversionRateScale())); uint208 ppsPrev = state.investmentStates[token].strategyAssetsPerShareSnapshot; if (ppsPrev == 0 || shares == 0 || ppsNow == ppsPrev) { @@ -61,13 +66,13 @@ library InvestmentVaultLib { } if (ppsNow > ppsPrev) { - uint208 grossDelta = uint208(Math.mulDiv(shares, uint256(ppsNow - ppsPrev), conversionRateScale)); + uint208 grossDelta = uint208(Math.mulDiv(shares, uint256(ppsNow - ppsPrev), conversionRateScale())); uint208 curatorPerformanceFee = uint208(Math.mulDiv(grossDelta, state.manager.getCuratorPerformanceFee(), state.manager.getFeeScale())); return (grossDelta - curatorPerformanceFee, true, curatorPerformanceFee, ppsNow); } - uint208 lossDelta = uint208(Math.mulDiv(shares, uint256(ppsPrev - ppsNow), conversionRateScale)); + uint208 lossDelta = uint208(Math.mulDiv(shares, uint256(ppsPrev - ppsNow), conversionRateScale())); return (lossDelta, false, 0, ppsNow); } @@ -79,7 +84,7 @@ library InvestmentVaultLib { * @param token The address of the token. */ function allocate(State storage state, address token) external { - IERC4626Strategy strategyVault = IERC4626Strategy(state.investmentStrategyVault[token]); + IERC4626 strategyVault = IERC4626(state.investmentStrategyVault[token]); uint208 assets = uint208(IERC20(token).balanceOf(address(this))); uint208 offset = state.manager.getInvestmentStrategyAssetsOffset(token); if (assets == 0 || assets < offset) { @@ -102,7 +107,7 @@ library InvestmentVaultLib { * @param token The address of the token. */ function withdrawAll(State storage state, address token) external { - IERC4626Strategy strategyVault = IERC4626Strategy(state.investmentStrategyVault[token]); + IERC4626 strategyVault = IERC4626(state.investmentStrategyVault[token]); uint256 shares = strategyVault.balanceOf(address(this)); if (shares == 0) { return; @@ -114,7 +119,7 @@ library InvestmentVaultLib { /** * @notice Withdraws assets to `receiver` in a single transaction. * @dev Evaluated in order. `idle` is this contract token balance; `strategyLiquidity` is - * `IERC4626Strategy.totalAssets()` on the strategy vault. + * `IERC4626.convertToAssets(balanceOf(address(this)))` on the strategy vault. * 1. Buffer preference: if `amount <= idle / 3`, satisfy from idle only (no strategy call). * 2. Else if `amount <= strategyLiquidity`, withdraw entirely from the strategy; idle unchanged. * 3. Else if `amount <= idle`, satisfy from idle only (withdrawal exceeds one third of idle but @@ -132,10 +137,10 @@ library InvestmentVaultLib { } IERC20 asset = IERC20(token); - IERC4626Strategy strategyVault = IERC4626Strategy(state.investmentStrategyVault[token]); + IERC4626 strategyVault = IERC4626(state.investmentStrategyVault[token]); uint208 idle = uint208(asset.balanceOf(address(this))); - uint208 strategyLiquidity = uint208(strategyVault.totalAssets()); + uint208 strategyLiquidity = uint208(strategyVault.convertToAssets(strategyVault.balanceOf(address(this)))); if (amount <= idle / 3) { asset.safeTransfer(receiver, amount); diff --git a/src/vault/Vault.sol b/src/vault/Vault.sol index c76a2c9..f24f4d0 100644 --- a/src/vault/Vault.sol +++ b/src/vault/Vault.sol @@ -57,8 +57,7 @@ contract Vault is * @param authority The address of the authority. * @param dropMerkleRoot The drop merkle root. * @param token The address of the token. - * @param aavePool The address of the aave pool. - * @param aToken The address of the a token. + * @param strategyVault The address of the strategy vault. */ function initialize( address verifiers, @@ -67,8 +66,7 @@ contract Vault is address authority, bytes32 dropMerkleRoot, address token, - address aavePool, - address aToken + address strategyVault ) public initializer { __UUPSUpgradeable_init(); __ReentrancyGuard_init(); @@ -78,13 +76,14 @@ contract Vault is revert ProtocolManagerAuthorityMismatch(); } VaultInitLib.init_unchained( - _getStorage(), verifiers, trustedForwarder, protocolManager, dropMerkleRoot, token, aavePool, aToken + _getStorage(), verifiers, trustedForwarder, protocolManager, dropMerkleRoot, token, strategyVault ); } /// @inheritdoc IVault - function approveUpgrade(address newImplementation) external restricted { + function approveUpgrade(address newImplementation, bytes32 paramsHash) external restricted { _getStorage().approvedImplementation = newImplementation; + _getStorage().approvedUpgradeParamsHash = paramsHash; } /** diff --git a/src/vault/Vault.types.sol b/src/vault/Vault.types.sol index e943627..0a2fb58 100644 --- a/src/vault/Vault.types.sol +++ b/src/vault/Vault.types.sol @@ -142,8 +142,9 @@ interface IVault is IVaultEvents { * @notice Approves the upgrade of the vault * @dev This function is called to approve the upgrade of the vault with particular implementation. * @param newImplementation The address of the new implementation. + * @param paramsHash The hash of the upgrade initialization parameters. */ - function approveUpgrade(address newImplementation) external; + function approveUpgrade(address newImplementation, bytes32 paramsHash) external; /** * @notice Deposit tokens with commitments and ZK proof validation diff --git a/src/vault/VaultInit.lib.sol b/src/vault/VaultInit.lib.sol index b86580f..59d9abd 100644 --- a/src/vault/VaultInit.lib.sol +++ b/src/vault/VaultInit.lib.sol @@ -6,7 +6,6 @@ import {IProtocolManager} from "src/ProtocolManager.types.sol"; import {Verifiers} from "src/vault/Verifiers.sol"; import {ITokenDistributor} from "src/token/TokenDistributor.types.sol"; import {TokenDistributorDeployLib} from "src/token/TokenDistributorDeploy.lib.sol"; -import {AaveVaultDeployerLib} from "src/aave/AaveVaultDeployer.lib.sol"; import {InvestmentVaultLib} from "src/vault/InvestmentVault.lib.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -26,8 +25,7 @@ library VaultInitLib { * @param protocolManager The address of the protocol manager. * @param dropMerkleRoot The drop merkle root. * @param token The address of the token. - * @param aavePool The address of the aave pool. - * @param aToken The address of the a token. + * @param strategyVault The address of the investment strategy vault. */ function init_unchained( State storage state, @@ -36,15 +34,13 @@ library VaultInitLib { address protocolManager, bytes32 dropMerkleRoot, address token, - address aavePool, - address aToken + address strategyVault ) external { state.trustedForwarder = trustedForwarder; state.manager = IProtocolManager(protocolManager); state.verifiers = Verifiers(verifiers); state.tokenDistributor = ITokenDistributor(TokenDistributorDeployLib.deployTokenDistributorImpl(dropMerkleRoot, token, address(this))); - address strategyVault = AaveVaultDeployerLib.deployAaveVaultImpl(aavePool, token, aToken); IERC20(token).forceApprove(strategyVault, type(uint208).max); state.investmentStrategyVault[token] = strategyVault; InvestmentVaultLib.snapshotStrategyDelta(state, token); diff --git a/src/vault/VaultStorage.sol b/src/vault/VaultStorage.sol index 8936254..63f0141 100644 --- a/src/vault/VaultStorage.sol +++ b/src/vault/VaultStorage.sol @@ -16,6 +16,7 @@ struct State { IProtocolManager manager; ITokenDistributor tokenDistributor; address approvedImplementation; + bytes32 approvedUpgradeParamsHash; /// @dev Gap for future upgrades uint256[50] __gap; } diff --git a/src/vault/VaultV2.sol b/src/vault/VaultV2.sol deleted file mode 100644 index 2a43a64..0000000 --- a/src/vault/VaultV2.sol +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.21; - -import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; -import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; -import {AccessManagedUpgradeable} from - "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; - -// not upgradable contracts & interfaces -import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; -import { - IVault, - IVaultErrors, - CommitmentRecord, - DepositParams, - Transaction, - ICommitmentsRecipient -} from "src/vault/Vault.types.sol"; - -// libs -import {VaultStorage} from "src/vault/VaultStorage.sol"; -import {InvestmentVaultLib} from "src/vault/InvestmentVault.lib.sol"; -import {InputModifierLib} from "src/vault/InputModifier.lib.sol"; -import {VaultDepositLib} from "src/vault/VaultDeposit.lib.sol"; -import {VaultSpendLib} from "src/vault/VaultSpend.lib.sol"; -import {InterestLib} from "src/vault/Interest.lib.sol"; - -/** - * @title VaultV2 - * @notice The main Zeroledger contract and entry point for the protocol. - * @dev Zeroldger token & token distributor are immutable and cannot be upgraded. - * @author ZeroLedger - */ -contract VaultV2 is - VaultStorage, - Initializable, - UUPSUpgradeable, - AccessManagedUpgradeable, - ReentrancyGuardUpgradeable, - PausableUpgradeable, - IVault, - IVaultErrors -{ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - - /** - * @notice Upgrades the vault - * @dev This function is called by the upgradeable contract after the upgrade. - * This can be used for new initializations and for tracking the upgrade version. - */ - function upgradeCallBack() external reinitializer(2) {} - - /// @inheritdoc IVault - function approveUpgrade(address newImplementation) external restricted { - _getStorage().approvedImplementation = newImplementation; - } - - /** - * @notice Authorizes the upgrade - * @dev This function is called to authorize the upgrade of Vault proxy with particular implementation. - * @param newImplementation The address of the new implementation. - */ - function _authorizeUpgrade(address newImplementation) internal view override { - require(_getStorage().approvedImplementation == newImplementation, "Implementation not approved"); - } - - /// @inheritdoc IVault - function isTrustedForwarder(address forwarder) public view virtual returns (bool) { - return _getStorage().trustedForwarder == forwarder; - } - - /** - * @notice Override for `msg.sender`. - * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever - * a call is not performed by the trusted forwarder or the calldata length - * is less than 20 bytes (an address length). - * @return The computed `msg.sender`. - */ - function _msgSender() internal view override returns (address) { - uint256 calldataLength = msg.data.length; - uint256 contextSuffixLength = _contextSuffixLength(); - if (calldataLength >= contextSuffixLength && isTrustedForwarder(msg.sender)) { - unchecked { - return address(bytes20(msg.data[calldataLength - contextSuffixLength:])); - } - } else { - return super._msgSender(); - } - } - - /** - * @notice Override for `msg.data`. - * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever - * a call is not performed by the trusted forwarder or the calldata length - * is less than 20 bytes (an address length). - * @return The computed `msg.data`. - */ - function _msgData() internal view override returns (bytes calldata) { - uint256 calldataLength = msg.data.length; - uint256 contextSuffixLength = _contextSuffixLength(); - if (calldataLength >= contextSuffixLength && isTrustedForwarder(msg.sender)) { - unchecked { - return msg.data[:calldataLength - contextSuffixLength]; - } - } else { - return super._msgData(); - } - } - - /// @notice ERC-2771 specifies the context as being a single address (20 bytes). - /// @return The context suffix length. - function _contextSuffixLength() internal pure override returns (uint256) { - return 20; - } - - /// @inheritdoc IVault - function pause() external restricted { - _pause(); - } - - /// @inheritdoc IVault - function unpause() external restricted { - _unpause(); - } - - /// @inheritdoc IVault - function deposit(DepositParams calldata depositParams, uint256[24] calldata proof) - external - nonReentrant - whenNotPaused - { - VaultDepositLib.deposit(_getStorage(), _msgSender(), depositParams, proof); - } - - /// @inheritdoc IVault - function depositWithPermit( - DepositParams calldata depositParams, - uint256[24] calldata proof, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external nonReentrant whenNotPaused { - address from = _msgSender(); - IERC20Permit(depositParams.token).permit(from, address(this), depositParams.amount, deadline, v, r, s); - VaultDepositLib.deposit(_getStorage(), from, depositParams, proof); - } - - /// @inheritdoc IVault - function spend(Transaction calldata transaction, uint256[24] calldata proof) external nonReentrant whenNotPaused { - VaultSpendLib.spend(_getStorage(), _msgSender(), transaction, proof); - } - - /// @inheritdoc IVault - function spendAndCall(address to, Transaction calldata transaction, uint256[24] calldata proof, bytes calldata data) - external - nonReentrant - whenNotPaused - { - VaultSpendLib.spend(_getStorage(), _msgSender(), transaction, proof); - ICommitmentsRecipient(to).onCommitmentsReceived(_msgSender(), transaction, data); - } - - /// @inheritdoc IVault - function getCuratorPerformanceFeeToCollect(address token) external view returns (uint208) { - return _getStorage().investmentStates[token].curatorPerformanceFeeToCollect; - } - - /// @inheritdoc IVault - function collectCuratorPerformanceFee(address token) external nonReentrant restricted { - address receiver = _msgSender(); - uint208 curatorPerformanceFee = InvestmentVaultLib.collectCuratorPerformanceFee(_getStorage(), token, receiver); - emit CuratorPerformanceFeeCollected(token, receiver, curatorPerformanceFee); - } - - /// @inheritdoc IVault - function previewFactors(address token, uint256[] calldata poseidonHashes) - external - view - returns (uint256[] memory factors) - { - return InputModifierLib.previewFactors(_getStorage(), token, poseidonHashes); - } - - /// @inheritdoc IVault - function assetsPerScaledShare(address token) external view returns (uint256) { - return InterestLib.assetsPerScaledShare(_getStorage(), token); - } - - /// @inheritdoc IVault - function getInvestmentStrategyVault(address token) external view returns (address) { - return _getStorage().investmentStrategyVault[token]; - } - - /// @inheritdoc IVault - function getCommitment(address token, uint256 poseidonHash) external view returns (CommitmentRecord memory) { - return _getStorage().commitmentsMap[token][poseidonHash]; - } - - /// @inheritdoc IVault - function getTrustedForwarder() external view returns (address) { - return _getStorage().trustedForwarder; - } - - /// @inheritdoc IVault - function getManager() external view returns (address) { - return address(_getStorage().manager); - } - - /// @inheritdoc IVault - function getVerifiers() external view returns (address) { - return address(_getStorage().verifiers); - } - - /// @inheritdoc IVault - function getTokenDistributor() external view returns (address) { - return address(_getStorage().tokenDistributor); - } -} diff --git a/test/InvestmentVault.lib.t.sol b/test/InvestmentVault.lib.t.sol index 7ab2c72..bccd3f7 100644 --- a/test/InvestmentVault.lib.t.sol +++ b/test/InvestmentVault.lib.t.sol @@ -160,7 +160,7 @@ contract InvestmentVaultLibTest is Test { (uint208 delta, bool isGain) = harness.snapshotStrategyDelta(address(token)); assertEq(delta, 0); assertTrue(isGain); - assertEq(harness.ppsSnapshot(address(token)), uint208(strategy.convertToAssets(strategy.conversionRateScale()))); + assertEq(harness.ppsSnapshot(address(token)), uint208(strategy.convertToAssets(InvestmentVaultLib.conversionRateScale()))); } function test_snapshotGains_gain_adds_curator_fee_and_returns_net() public { diff --git a/test/Vault.spend11.t.sol b/test/Vault.spend11.t.sol index c824689..db14f88 100644 --- a/test/Vault.spend11.t.sol +++ b/test/Vault.spend11.t.sol @@ -95,7 +95,9 @@ contract VaultSpend11Test is VaultTest, IVaultEvents { vault.spend(txData, getDummyProof()); assertEq(getCommitmentOwner(address(mockToken), inputHash), address(0), "Input commitment should be removed"); - assertEq(getCommitmentOwner(address(mockToken), outputHash), alice, "Output commitment should be assigned to Alice"); + assertEq( + getCommitmentOwner(address(mockToken), outputHash), alice, "Output commitment should be assigned to Alice" + ); assertEq(inputOwnerBefore, alice, "Input commitment should have been assigned to Alice"); assertEq(outputOwnerBefore, address(0), "Output commitment should not have existed before"); } @@ -205,8 +207,7 @@ contract VaultSpend11Test is VaultTest, IVaultEvents { uint208 oversize = netAmount + 1; - Transaction memory txData = - _buildSpend11(address(mockToken), depositHashes[0], 4001, alice, oversize, bob, 0); + Transaction memory txData = _buildSpend11(address(mockToken), depositHashes[0], 4001, alice, oversize, bob, 0); spend11Verifier.setVerificationResult(true); @@ -229,8 +230,7 @@ contract VaultSpend11Test is VaultTest, IVaultEvents { uint208 vaultBalance = uint208(mockToken.balanceOf(address(vault))); uint208 publicOut = uint208(bound(netAmount / 2, 1, vaultBalance)); - Transaction memory txData = - _buildSpend11(address(mockToken), depositHashes[0], 6001, alice, publicOut, bob, 0); + Transaction memory txData = _buildSpend11(address(mockToken), depositHashes[0], 6001, alice, publicOut, bob, 0); spend11Verifier.setVerificationResult(true); CommitmentsRecipientMock recipient = new CommitmentsRecipientMock(); diff --git a/test/VaultTest.util.sol b/test/VaultTest.util.sol index 40c818a..f1b76da 100644 --- a/test/VaultTest.util.sol +++ b/test/VaultTest.util.sol @@ -12,8 +12,7 @@ import {Forwarder} from "src/Forwarder.sol"; import {ProtocolManager, Fees} from "src/ProtocolManager.sol"; import {Administrator} from "src/Administrator.sol"; import {MockERC20} from "src/helpers/MockERC20.sol"; -import {MockAToken} from "src/helpers/MockAToken.sol"; -import {MockAavePool} from "src/helpers/MockAavePool.sol"; +import {MockMorphoVault} from "src/helpers/MockMorphoVault.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {MockVerifier} from "./mocks/MockVerifier.sol"; import {DepositParams, DepositCommitmentParams, IVaultErrors} from "src/vault/Vault.types.sol"; @@ -36,6 +35,7 @@ contract VaultTest is Test, IVaultErrors { MockVerifier internal spend161Verifier; Forwarder internal zeroLedgerForwarder; MockERC20 internal mockToken; + MockMorphoVault internal mockStrategyVault; ProtocolManager internal protocolManager; PermitUtils internal permitUtils; address internal paymaster = makeAddr("paymaster"); @@ -88,8 +88,7 @@ contract VaultTest is Test, IVaultErrors { zeroLedgerForwarder = new Forwarder(); - MockAavePool mockPool = new MockAavePool(address(mockToken)); - MockAToken mockAToken = mockPool.aToken(); + mockStrategyVault = new MockMorphoVault(mockToken); ERC1967Proxy vaultProxy = new ERC1967Proxy(address(new Vault()), ""); vault = Vault(address(vaultProxy)); @@ -100,8 +99,7 @@ contract VaultTest is Test, IVaultErrors { address(administrator), bytes32(0), address(mockToken), - address(mockPool), - address(mockAToken) + address(mockStrategyVault) ); // Create deterministic test accounts with private keys for signing