diff --git a/abi/IVault.json b/abi/IVault.json index 76fcd66..2633209 100644 --- a/abi/IVault.json +++ b/abi/IVault.json @@ -56,6 +56,12 @@ "internalType": "uint256", "name": "poseidonHash", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "factor", + "type": "uint256" } ], "name": "CommitmentRemoved", diff --git a/abi/IVaultEvents.json b/abi/IVaultEvents.json index 99f686a..28fc698 100644 --- a/abi/IVaultEvents.json +++ b/abi/IVaultEvents.json @@ -56,6 +56,12 @@ "internalType": "uint256", "name": "poseidonHash", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "factor", + "type": "uint256" } ], "name": "CommitmentRemoved", diff --git a/abi/Vault.json b/abi/Vault.json index ee43441..7b9b514 100644 --- a/abi/Vault.json +++ b/abi/Vault.json @@ -291,6 +291,12 @@ "internalType": "uint256", "name": "poseidonHash", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "factor", + "type": "uint256" } ], "name": "CommitmentRemoved", diff --git a/abi/VaultSpendLib.json b/abi/VaultSpendLib.json index c3ed50f..cf32c35 100644 --- a/abi/VaultSpendLib.json +++ b/abi/VaultSpendLib.json @@ -110,6 +110,12 @@ "internalType": "uint256", "name": "poseidonHash", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "factor", + "type": "uint256" } ], "name": "CommitmentRemoved", diff --git a/ignition/deployments/chain-8453/deployed_addresses.json b/ignition/deployments/chain-8453/deployed_addresses.json index f54b7e4..886bd3f 100644 --- a/ignition/deployments/chain-8453/deployed_addresses.json +++ b/ignition/deployments/chain-8453/deployed_addresses.json @@ -12,20 +12,22 @@ "Main#Spend61Verifier": "0xb326b4c7d6CcE4e52a4F26eF3B9887970a3bF189", "Main#Spend121Verifier": "0xfb36dc2d86652d90960da47b7485E246EC895369", "Main#Verifiers": "0xfaf0cc3f0A38021f9d873130ACc62F7824Fc339D", - "Main#Administrator_0": "0x86f5A233a477fd2Fd338F294Ae7277407b60655a", - "Main#Forwarder_0": "0xf3430970980d60BEEcEcC5f72b3868B891127c83", - "Main#InvoiceFactory_0": "0xaAc5Dfc0Cb60b5F829e67749a72101A9d7C67FaD", - "Main#TokenDistributorDeployLib_0": "0xe279F01DF9a69695D3203009be176dbB36106241", - "Main#InterestLib_0": "0xe8426F0675C9Da7340b4E8801cDE6a5C59f23Eb7", - "Main#VaultMathLib_0": "0x67bCC483fAaD61c3B7eBAdb31c884b8Aba9A13Ff", - "Main#InputsLib_0": "0x8B77b2Bf6A592361aF18803d785c25a1BBE1104c", - "Main#InvestmentVaultLib_0": "0x3B0775204AF03c2E9940CfbCB9fbeA0949CadA7B", - "Main#InputModifierLib_0": "0x47F8FB8136BFAFb9791D4C0CBf8e0764b02D619e", - "Main#VaultInitLib_0": "0x262166E3d46dA3a796BF7BE448bdddfd11FFB56f", - "Main#VaultDepositLib_0": "0x60d879820974964b793B60a9FA14103B7f9527B0", - "Main#VaultSpendLib_0": "0x421DA02Cb0C0f457F96abF719A48ef61E78c3376", - "Main#Vault_0": "0xA92aA9b65d2D5b6C9a5Af2C4365357A304FC247B", + "Main#Administrator": "0x86f5A233a477fd2Fd338F294Ae7277407b60655a", + "Main#Forwarder": "0xf3430970980d60BEEcEcC5f72b3868B891127c83", + "Main#InvoiceFactory": "0xaAc5Dfc0Cb60b5F829e67749a72101A9d7C67FaD", + "Main#TokenDistributorDeployLib": "0xe279F01DF9a69695D3203009be176dbB36106241", + "Main#InterestLib": "0xe8426F0675C9Da7340b4E8801cDE6a5C59f23Eb7", + "Main#VaultMathLib": "0x67bCC483fAaD61c3B7eBAdb31c884b8Aba9A13Ff", + "Main#InputsLib": "0x8B77b2Bf6A592361aF18803d785c25a1BBE1104c", + "Main#InvestmentVaultLib": "0x3B0775204AF03c2E9940CfbCB9fbeA0949CadA7B", + "Main#InputModifierLib": "0x47F8FB8136BFAFb9791D4C0CBf8e0764b02D619e", + "Main#VaultInitLib": "0x262166E3d46dA3a796BF7BE448bdddfd11FFB56f", + "Main#VaultDepositLib": "0x60d879820974964b793B60a9FA14103B7f9527B0", + "Main#VaultSpendLib": "0x421DA02Cb0C0f457F96abF719A48ef61E78c3376", + "Main#VaultImplementation": "0xA92aA9b65d2D5b6C9a5Af2C4365357A304FC247B", "Main#VaultProxy": "0xE0Eefe4AA0cB32740aDFD8083AbeC255AaC3b379", "Main#Vault": "0xE0Eefe4AA0cB32740aDFD8083AbeC255AaC3b379", - "Main#ProtocolManager": "0xCC499487F6a1780dB9410a65408B98E63346aCfe" + "Main#ProtocolManager": "0xCC499487F6a1780dB9410a65408B98E63346aCfe", + "VaultUpgradeProd#VaultSpendLib": "0x94CE27CDFD55208678FB250FeD21B7f1FfdEc4Ff", + "VaultUpgradeProd#VaultImplementation": "0x5Bb28C730A85D2C5Ea834592b6D06a444D607AB7" } diff --git a/ignition/modules/VaultUpgrade.module.ts b/ignition/modules/VaultUpgrade.module.ts index 7a53243..e276f69 100644 --- a/ignition/modules/VaultUpgrade.module.ts +++ b/ignition/modules/VaultUpgrade.module.ts @@ -1,41 +1,19 @@ import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; -export default buildModule("VaultUpgrade", (m) => { - const interestLib = m.library("InterestLib", { - id: `InterestLib_${process.env.VERSION_TAG ?? 0}`, - }); - const vaultMathLib = m.library("VaultMathLib", { - id: `VaultMathLib_${process.env.VERSION_TAG ?? 0}`, - after: [interestLib], - }); +export default buildModule("VaultUpgradeProd", (m) => { + const interestLib = m.contractAt("InterestLib", "0xe8426F0675C9Da7340b4E8801cDE6a5C59f23Eb7"); + const vaultMathLib = m.contractAt("VaultMathLib", "0x67bCC483fAaD61c3B7eBAdb31c884b8Aba9A13Ff"); - const inputsLib = m.library("InputsLib", { - id: `InputsLib_${process.env.VERSION_TAG ?? 0}`, - after: [vaultMathLib], - }); + const inputsLib = m.contractAt("InputsLib", "0x8B77b2Bf6A592361aF18803d785c25a1BBE1104c"); - const investmentVaultLib = m.library("InvestmentVaultLib", { - id: `InvestmentVaultLib_${process.env.VERSION_TAG ?? 0}`, - after: [inputsLib], - }); + const investmentVaultLib = m.contractAt("InvestmentVaultLib", "0x3B0775204AF03c2E9940CfbCB9fbeA0949CadA7B"); - const inputModifierLib = m.library("InputModifierLib", { - id: `InputModifierLib_${process.env.VERSION_TAG ?? 0}`, - libraries: { VaultMathLib: vaultMathLib, InterestLib: interestLib, InvestmentVaultLib: investmentVaultLib }, - }); + const inputModifierLib = m.contractAt("InputModifierLib", "0x47F8FB8136BFAFb9791D4C0CBf8e0764b02D619e"); - const vaultDepositLib = m.library("VaultDepositLib", { - id: `VaultDepositLib_${process.env.VERSION_TAG ?? 0}`, - libraries: { - VaultMathLib: vaultMathLib, - InterestLib: interestLib, - InvestmentVaultLib: investmentVaultLib, - InputsLib: inputsLib, - }, - }); + const vaultDepositLib = m.contractAt("VaultDepositLib", "0x60d879820974964b793B60a9FA14103B7f9527B0"); const vaultSpendLib = m.library("VaultSpendLib", { - id: `VaultSpendLib_${process.env.VERSION_TAG ?? 0}`, + id: `VaultSpendLib_1`, libraries: { VaultMathLib: vaultMathLib, InterestLib: interestLib, @@ -44,15 +22,19 @@ export default buildModule("VaultUpgrade", (m) => { }, after: [vaultDepositLib], }); - const newImplementation = m.contract("VaultV2", [], { + + const vaultInitLib = m.contractAt("VaultInitLib", "0x262166E3d46dA3a796BF7BE448bdddfd11FFB56f"); + + const newImplementation = m.contract("Vault", [], { libraries: { InvestmentVaultLib: investmentVaultLib, InputModifierLib: inputModifierLib, + VaultInitLib: vaultInitLib, VaultDepositLib: vaultDepositLib, VaultSpendLib: vaultSpendLib, InterestLib: interestLib, }, - id: `Vault_${process.env.VERSION_TAG ?? 0}`, + id: `Vault_1`, after: [vaultSpendLib], }); diff --git a/package-lock.json b/package-lock.json index 091f543..87b4996 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.2.0", "license": "MIT", "dependencies": { - "@aave-dao/aave-address-book": "^4.48.1", "@openzeppelin/contracts": "^5.4.0", "@openzeppelin/contracts-upgradeable": "^5.4.0", "solady": "^0.1.26" @@ -41,18 +40,6 @@ "solidity-coverage": "^0.8.16" } }, - "node_modules/@aave-dao/aave-address-book": { - "version": "4.48.1", - "resolved": "https://registry.npmjs.org/@aave-dao/aave-address-book/-/aave-address-book-4.48.1.tgz", - "integrity": "sha512-LveDIK+IAF+LeA/HADSPG7bavN+gb448b9aIeYraO3FctDe4Wq1m7v14uJnfzpQaORCFMufbzxf7t0xv+aBIgw==", - "license": "MIT", - "workspaces": [ - "ui" - ], - "peerDependencies": { - "viem": "^2.23.5" - } - }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", @@ -2038,6 +2025,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "dev": true, "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -4874,6 +4862,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", + "dev": true, "license": "MIT", "peer": true, "funding": { @@ -7196,6 +7185,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, "license": "MIT" }, "node_modules/evp_bytestokey": { @@ -8890,6 +8880,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "dev": true, "funding": [ { "type": "github", @@ -10318,6 +10309,7 @@ "version": "0.8.6", "resolved": "https://registry.npmjs.org/ox/-/ox-0.8.6.tgz", "integrity": "sha512-eiKcgiVVEGDtEpEdFi1EGoVVI48j6icXHce9nFwCNM7CKG3uoCXKdr4TPhS00Iy1TR2aWSF1ltPD0x/YgqIL9w==", + "dev": true, "funding": [ { "type": "github", @@ -10349,6 +10341,7 @@ "version": "1.11.0", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz", "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==", + "dev": true, "license": "MIT", "peer": true }, @@ -10356,6 +10349,7 @@ "version": "1.9.7", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -10372,6 +10366,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -10385,6 +10380,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, "license": "MIT", "peer": true, "funding": { @@ -10395,6 +10391,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -10410,6 +10407,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -12781,7 +12779,7 @@ "version": "5.4.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", - "devOptional": true, + "dev": true, "peer": true, "bin": { "tsc": "bin/tsc", @@ -12907,6 +12905,7 @@ "version": "2.33.3", "resolved": "https://registry.npmjs.org/viem/-/viem-2.33.3.tgz", "integrity": "sha512-aWDr6i6r3OfNCs0h9IieHFhn7xQJJ8YsuA49+9T5JRyGGAkWhLgcbLq2YMecgwM7HdUZpx1vPugZjsShqNi7Gw==", + "dev": true, "funding": [ { "type": "github", @@ -12938,6 +12937,7 @@ "version": "1.9.2", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -12954,6 +12954,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -12967,6 +12968,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, "license": "MIT", "peer": true, "funding": { @@ -12977,6 +12979,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -12992,6 +12995,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -13006,6 +13010,7 @@ "version": "8.18.2", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -13336,6 +13341,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/scripts/deploy.ts b/scripts/deploy.ts index edc6849..37abb7b 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -4,6 +4,7 @@ import { NetworkConfig } from "hardhat/types"; import { mkCreateXSalt } from "./mkCreateXSalt"; import MocksModule from "../ignition/modules/Mocks.module"; import { deploymentChange } from "./deploymentChange"; +import { getIgnitionConfig } from "./getIgnitionConfig"; type Params = { admin: string; @@ -28,28 +29,7 @@ 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: 2, - }; - break; - default: - ignitionConfig = { - blockPollingInterval: 1900, - requiredConfirmations: 15, - }; - break; - } + const ignitionConfig = await getIgnitionConfig(hre.network.name); const rawParams = ( hre.network.config as NetworkConfig & { diff --git a/scripts/deployVaultUpgrade.ts b/scripts/deployVaultUpgrade.ts index 42c6a31..ae3947e 100644 --- a/scripts/deployVaultUpgrade.ts +++ b/scripts/deployVaultUpgrade.ts @@ -1,9 +1,9 @@ import hre from "hardhat"; import { NetworkConfig } from "hardhat/types"; import { mkCreateXSalt } from "./mkCreateXSalt"; -import ignitionConfig from "./ignition.config"; import VaultUpgradeModule from "../ignition/modules/VaultUpgrade.module"; import { deploymentChange } from "./deploymentChange"; +import { getIgnitionConfig } from "./getIgnitionConfig"; type Params = { donor?: string; @@ -23,6 +23,8 @@ async function main() { ).params, }; + const ignitionConfig = await getIgnitionConfig(hre.network.name); + const salt = mkCreateXSalt(deployer.address, params.rnd11Input!); const { newImplementation } = await hre.ignition.deploy(VaultUpgradeModule, { @@ -35,7 +37,9 @@ async function main() { const newImplementationAddress = await newImplementation.getAddress(); - console.log(`New vault implementation deployed. Address: ${newImplementationAddress}`); + console.log( + `New vault implementation deployed. Address: ${newImplementationAddress}, empty bytes params hash: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470`, + ); await deploymentChange(deployer, params.donor); } diff --git a/scripts/getIgnitionConfig.ts b/scripts/getIgnitionConfig.ts new file mode 100644 index 0000000..5fac6fa --- /dev/null +++ b/scripts/getIgnitionConfig.ts @@ -0,0 +1,19 @@ +export const getIgnitionConfig = async (network: string) => { + switch (network) { + case "hardhat": + return { + blockPollingInterval: 1500, + requiredConfirmations: 2, + }; + case "localhost": + return { + blockPollingInterval: 1500, + requiredConfirmations: 2, + }; + default: + return { + blockPollingInterval: 1900, + requiredConfirmations: 15, + }; + } +}; diff --git a/src/helpers/MockMorphoVault.sol b/src/helpers/MockMorphoVault.sol index 6375467..711ed9a 100644 --- a/src/helpers/MockMorphoVault.sol +++ b/src/helpers/MockMorphoVault.sol @@ -5,9 +5,10 @@ import {ERC4626, ERC20} from "@openzeppelin/contracts/token/ERC20/extensions/ERC 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())) {} + 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 { diff --git a/src/vault/Vault.sol b/src/vault/Vault.sol index 07a7296..1870273 100644 --- a/src/vault/Vault.sol +++ b/src/vault/Vault.sol @@ -5,9 +5,8 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U 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"; +import {AccessManagedUpgradeable} from + "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; // not upgradable contracts & interfaces import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; @@ -78,13 +77,7 @@ contract Vault is revert ProtocolManagerAuthorityMismatch(); } VaultInitLib.init_unchained( - _getStorage(), - verifiers, - trustedForwarder, - protocolManager, - dropMerkleRoot, - token, - strategyVault + _getStorage(), verifiers, trustedForwarder, protocolManager, dropMerkleRoot, token, strategyVault ); } @@ -179,10 +172,11 @@ contract Vault is } /// @inheritdoc IVault - function deposit( - DepositParams calldata depositParams, - uint256[24] calldata proof - ) external nonReentrant whenNotPaused { + function deposit(DepositParams calldata depositParams, uint256[24] calldata proof) + external + nonReentrant + whenNotPaused + { VaultDepositLib.deposit(_getStorage(), _msgSender(), depositParams, proof); } @@ -196,7 +190,8 @@ contract Vault is bytes32 s ) external nonReentrant whenNotPaused { address from = _msgSender(); - IERC20Permit(depositParams.token).permit(from, address(this), depositParams.amount, deadline, v, r, s); + try IERC20Permit(depositParams.token).permit(from, address(this), depositParams.amount, deadline, v, r, s) {} + catch {} VaultDepositLib.deposit(_getStorage(), from, depositParams, proof); } @@ -206,12 +201,11 @@ contract Vault is } /// @inheritdoc IVault - function spendAndCall( - address to, - Transaction calldata transaction, - uint256[24] calldata proof, - bytes calldata data - ) external nonReentrant whenNotPaused { + 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); } @@ -229,10 +223,11 @@ contract Vault is } /// @inheritdoc IVault - function previewFactors( - address token, - uint256[] calldata poseidonHashes - ) external view returns (uint256[] memory factors) { + function previewFactors(address token, uint256[] calldata poseidonHashes) + external + view + returns (uint256[] memory factors) + { return InputModifierLib.previewFactors(_getStorage(), token, poseidonHashes); } diff --git a/src/vault/Vault.types.sol b/src/vault/Vault.types.sol index 167e554..22a8790 100644 --- a/src/vault/Vault.types.sol +++ b/src/vault/Vault.types.sol @@ -87,8 +87,9 @@ interface IVaultEvents { * @param owner The owner of the commitment * @param token The token that the commitment is in scope of * @param poseidonHash The poseidon hash of the commitment + * @param factor The factor of the commitment */ - event CommitmentRemoved(address indexed owner, address indexed token, uint256 poseidonHash); + event CommitmentRemoved(address indexed owner, address indexed token, uint256 poseidonHash, uint256 factor); /** * @notice Emitted when curator performance fee is collected for a specific token diff --git a/src/vault/VaultSpend.lib.sol b/src/vault/VaultSpend.lib.sol index 679e9e0..340f237 100644 --- a/src/vault/VaultSpend.lib.sol +++ b/src/vault/VaultSpend.lib.sol @@ -33,7 +33,7 @@ library VaultSpendLib { revert IVaultErrors.InputCommitmentNotFound(inputHash); } delete state.commitmentsMap[transaction.token][inputHash]; - emit IVaultEvents.CommitmentRemoved(inputOwner, transaction.token, inputHash); + emit IVaultEvents.CommitmentRemoved(inputOwner, transaction.token, inputHash, transaction.inputsFactors[i]); } } diff --git a/test/Administrator.t.sol b/test/Administrator.t.sol index 8a4696e..e2ed302 100644 --- a/test/Administrator.t.sol +++ b/test/Administrator.t.sol @@ -12,6 +12,8 @@ import {Fees} from "src/ProtocolManager.types.sol"; import {MockERC20} from "src/helpers/MockERC20.sol"; import {RolesLib} from "src/Roles.lib.sol"; +import "./VaultTest.util.sol"; + /// @dev Minimal vault stand-in: `AccessManaged` wiring plus `getManager()` (the `ProtocolManager` contract). contract VaultStub is AccessManaged { address private immutable _managerContract; @@ -97,3 +99,52 @@ contract AdministratorTest is Test { ); } } + +/// @dev Exercises `Vault.approveUpgrade` against `AccessManager` rules wired by `Administrator.setupGovernance`. +contract AdministratorApproveUpgradeTest is VaultTest { + function setUp() public { + baseSetup(); + } + + /// @dev Before `setupGovernance`, restricted selectors default to `ADMIN_ROLE` (id 0); constructor admin may call. + function test_approveUpgrade_succeeds_for_initial_admin_role_holder_before_governance() public { + address newImpl = makeAddr("newImpl"); + bytes32 paramsHash = keccak256(""); + vault.approveUpgrade(newImpl, paramsHash); + } + + /// @dev After governance, `approveUpgrade` is `RolesLib.MAINTAINER` only; execution delay is 0 for this test. + function test_approveUpgrade_succeeds_for_maintainer_after_setupGovernance() public { + address multisigAdmin = makeAddr("multisigAdmin"); + address maintAddr = makeAddr("maintainerAddr"); + address sc = makeAddr("securityCouncilAddr"); + address mgr = makeAddr("protocolManagerAddr"); + + uint32 upgradeDelayZero; + + administrator.setupGovernance(multisigAdmin, address(vault), maintAddr, sc, mgr, upgradeDelayZero, 86_400); + + address newImpl = makeAddr("newImplAfterGov"); + bytes32 paramsHash = keccak256(hex"01"); + + vm.prank(maintAddr); + vault.approveUpgrade(newImpl, paramsHash); + } + + /// @dev Multisig with `ADMIN_ROLE` grants self `MAINTAINER` (role admin defaults to admin), then approves. + function test_approveUpgrade_succeeds_for_admin_multisig_after_self_granting_maintainer() public { + address multisigAdmin = makeAddr("multisigAdmin2"); + address maintAddr = makeAddr("maintainerAddr2"); + address sc = makeAddr("securityCouncilAddr2"); + address mgr = makeAddr("protocolManagerAddr2"); + + administrator.setupGovernance(multisigAdmin, address(vault), maintAddr, sc, mgr, 0, 86_400); + + vm.startPrank(multisigAdmin); + administrator.grantRole(RolesLib.MAINTAINER, multisigAdmin, 0); + address newImpl = makeAddr("newImplAdminMaint"); + bytes32 paramsHash = keccak256(hex"ab"); + vault.approveUpgrade(newImpl, paramsHash); + vm.stopPrank(); + } +} diff --git a/test/InvestmentVault.lib.t.sol b/test/InvestmentVault.lib.t.sol index d07ab34..48695e9 100644 --- a/test/InvestmentVault.lib.t.sol +++ b/test/InvestmentVault.lib.t.sol @@ -172,7 +172,9 @@ 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(InvestmentVaultLib.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/ProtocolManager.t.sol b/test/ProtocolManager.t.sol index 9108d75..2a19ca9 100644 --- a/test/ProtocolManager.t.sol +++ b/test/ProtocolManager.t.sol @@ -70,9 +70,7 @@ contract ProtocolManagerTest is Test, IManagerErrors, IManagerEvents { uint208 maxSpendFee = uint208(Math.ceilDiv(token.totalSupply(), 100000)); // Deposit fee is hard-pinned to zero (H3); only withdraw/spend can go to their respective maxima. - manager.setFees( - address(token), Fees({spend: maxSpendFee, deposit: 0, withdraw: MAX_DEPOSIT_WITHDRAW_FEE}) - ); + manager.setFees(address(token), Fees({spend: maxSpendFee, deposit: 0, withdraw: MAX_DEPOSIT_WITHDRAW_FEE})); Fees memory fees = manager.getFees(address(token)); assertEq(fees.deposit, 0); assertEq(fees.withdraw, MAX_DEPOSIT_WITHDRAW_FEE); diff --git a/test/Vault.deposit.t.sol b/test/Vault.deposit.t.sol index e90ebbb..3f70768 100644 --- a/test/Vault.deposit.t.sol +++ b/test/Vault.deposit.t.sol @@ -16,11 +16,7 @@ contract VaultDepositTest is VaultTest, IVaultEvents { // Fuzzy test for various deposit amounts and fee scenarios. // Protocol policy (H3): deposit fee is hard-pinned to 0; only forwarderFee/maxTVL vary. - function testFuzz_deposit_amounts_and_fees( - uint208 depositAmount, - uint208 forwarderFee, - uint208 maxTVL - ) public { + function testFuzz_deposit_amounts_and_fees(uint208 depositAmount, uint208 forwarderFee, uint208 maxTVL) public { vm.assume(depositAmount <= type(uint208).max); vm.assume(forwarderFee < depositAmount / 2); // Reasonable forwarder fee vm.assume(maxTVL >= depositAmount - forwarderFee); diff --git a/test/Vault.spend.duplicate.t.sol b/test/Vault.spend.duplicate.t.sol index 163aa09..c1af1a6 100644 --- a/test/Vault.spend.duplicate.t.sol +++ b/test/Vault.spend.duplicate.t.sol @@ -4,9 +4,7 @@ pragma solidity >=0.8.21; // solhint-disable no-global-import import {VaultTest} from "./VaultTest.util.sol"; -import { - Transaction, OutputsOwners, PublicOutput, IVaultErrors, IVaultEvents -} from "src/vault/Vault.types.sol"; +import {Transaction, OutputsOwners, PublicOutput, IVaultErrors, IVaultEvents} from "src/vault/Vault.types.sol"; import {Fees} from "src/ProtocolManager.types.sol"; import {InputsLib} from "src/vault/Inputs.lib.sol"; @@ -265,13 +263,7 @@ contract VaultSpendDuplicateTest is VaultTest, IVaultEvents { createDeposit(alice, depositAmount, 0, 0, depositHashes, [alice, alice, charlie]); Transaction memory txData = _buildSpend22( - depositHashes[0], - depositHashes[1], - uint256(999000005), - uint256(999000006), - alice, - _emptyPublicOutputs(), - 0 + depositHashes[0], depositHashes[1], uint256(999000005), uint256(999000006), alice, _emptyPublicOutputs(), 0 ); spend22Verifier.setVerificationResult(true); @@ -399,9 +391,7 @@ contract VaultSpendDuplicateTest is VaultTest, IVaultEvents { vault.spend(txData, getDummyProof()); assertEq( - getCommitmentOwner(address(mockToken), uint256(999400006)), - alice, - "Shared-input-only spend must still succeed" + getCommitmentOwner(address(mockToken), uint256(999400006)), alice, "Shared-input-only spend must still succeed" ); } } diff --git a/test/Vault.spend11.t.sol b/test/Vault.spend11.t.sol index 47592c3..ec7c8d4 100644 --- a/test/Vault.spend11.t.sol +++ b/test/Vault.spend11.t.sol @@ -86,7 +86,7 @@ contract VaultSpend11Test is VaultTest, IVaultEvents { address outputOwnerBefore = getCommitmentOwner(address(mockToken), outputHash); vm.expectEmit(true, true, false, true); - emit CommitmentRemoved(alice, address(mockToken), inputHash); + emit CommitmentRemoved(alice, address(mockToken), inputHash, 0); vm.expectEmit(true, true, true, true); emit CommitmentCreated(alice, address(mockToken), alice, outputHash, "spend11_metadata"); @@ -188,10 +188,7 @@ contract VaultSpend11Test is VaultTest, IVaultEvents { assertEq(vault.getCommitment(address(mockToken), 2001).owner, alice); } - function testFuzz_spend11_reverts_on_oversized_public_withdraw( - uint96 netAmountRaw, - uint16 forwarderFeeRaw - ) public { + function testFuzz_spend11_reverts_on_oversized_public_withdraw(uint96 netAmountRaw, uint16 forwarderFeeRaw) public { uint208 netAmount = uint208(bound(netAmountRaw, 5e18, 400e18)); uint208 forwarderFee = uint208(bound(forwarderFeeRaw, 0, 2e18)); diff --git a/test/VaultTest.util.sol b/test/VaultTest.util.sol index f1b76da..55885dc 100644 --- a/test/VaultTest.util.sol +++ b/test/VaultTest.util.sol @@ -37,6 +37,7 @@ contract VaultTest is Test, IVaultErrors { MockERC20 internal mockToken; MockMorphoVault internal mockStrategyVault; ProtocolManager internal protocolManager; + Administrator internal administrator; PermitUtils internal permitUtils; address internal paymaster = makeAddr("paymaster"); address internal alice; @@ -78,7 +79,7 @@ contract VaultTest is Test, IVaultErrors { mockToken = new MockERC20("Test Token", "TEST"); permitUtils = new PermitUtils(mockToken.DOMAIN_SEPARATOR()); - Administrator administrator = new Administrator(address(this)); + administrator = new Administrator(address(this)); protocolManager = new ProtocolManager( address(administrator), address(mockToken), type(uint208).max, Fees({spend: 0, deposit: 0, withdraw: 0}), 0, 0