From 2a8f9f521473befda20e059b3a2e7b2e3f9b3b6d Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:03:51 +0400 Subject: [PATCH 1/2] Add deployment file for simplifying OUSD --- contracts/deploy/mainnet/155_simplify_ousd.js | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 contracts/deploy/mainnet/155_simplify_ousd.js diff --git a/contracts/deploy/mainnet/155_simplify_ousd.js b/contracts/deploy/mainnet/155_simplify_ousd.js new file mode 100644 index 0000000000..331f5fad11 --- /dev/null +++ b/contracts/deploy/mainnet/155_simplify_ousd.js @@ -0,0 +1,114 @@ +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { isFork } = require("../../test/helpers"); +const { impersonateAndFund } = require("../../utils/signers"); +const { setERC20TokenBalance } = require("../../test/_fund"); +const { parseUnits } = require("ethers").utils; + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "155_simplify_ousd", + forceDeploy: false, + //forceSkip: true, + reduceQueueTime: true, + deployerIsProposer: false, + proposalId: "", + }, + async ({ ethers }) => { + // Current contracts + const cVaultProxy = await ethers.getContract("VaultProxy"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); + const cUSDTStrategyProxy = await ethers.getContract( + "MorphoGauntletPrimeUSDTStrategyProxy" + ); + const cSSRStrategyProxy = await ethers.getContract("MakerSSRStrategyProxy"); + + if (isFork) { + // Impersonate the strategist + const strategist = await impersonateAndFund( + addresses.multichainStrategist + ); + + // Drain the strategies + await cVault + .connect(strategist) + .withdrawAllFromStrategy(cUSDTStrategyProxy.address); + console.log( + `Drained Gauntlet Prime USDT Strategy ${cUSDTStrategyProxy.address}` + ); + await cVault + .connect(strategist) + .withdrawAllFromStrategy(cSSRStrategyProxy.address); + console.log(`Drained SSR Strategy ${cSSRStrategyProxy.address}`); + + // Simulate asset swaps + const usdt = await ethers.getContractAt("IERC20", addresses.mainnet.USDT); + const usds = await ethers.getContractAt("IERC20", addresses.mainnet.USDS); + const usdc = await ethers.getContractAt("IERC20", addresses.mainnet.USDC); + + const usdtBalance = await usdt.balanceOf(cVault.address); + const usdsBalance = await usds.balanceOf(cVault.address); + const usdcNeeded = usdtBalance.add(usdsBalance.div(parseUnits("1", 12))); + + console.log(`USDT Balance: ${usdtBalance}`); + console.log(`USDS Balance: ${usdsBalance}`); + console.log(`USDC Needed: ${usdcNeeded}`); + + const vaultSigner = await impersonateAndFund(cVault.address); + await usdt.connect(vaultSigner).transfer(addresses.dead, usdtBalance); + console.log(`Transferred USDT to dead address ${addresses.dead}`); + await usds.connect(vaultSigner).transfer(addresses.dead, usdsBalance); + console.log(`Transferred USDS to dead address ${addresses.dead}`); + + await setERC20TokenBalance(cVault.address, usdc, usdcNeeded); + console.log(`Funded Vault with ${usdcNeeded} USDC`); + } + + // Governance Actions + // ---------------- + return { + name: `Simplify OUSD +This proposal simplifies OUSD by removing USDT and USDS (and their related strategies) from the Vault. + +The main objective is to make OUSD only be backed by USDC.`, + actions: [ + // 1. Remove default USDT strategy + { + contract: cVault, + signature: "setAssetDefaultStrategy(address,address)", + args: [addresses.mainnet.USDT, addresses.zero], + }, + // 2. Remove default USDS strategy + { + contract: cVault, + signature: "setAssetDefaultStrategy(address,address)", + args: [addresses.mainnet.USDS, addresses.zero], + }, + // 3. Remove Gauntlet Prime USDT Strategy + { + contract: cVault, + signature: "removeStrategy(address)", + args: [cUSDTStrategyProxy.address], + }, + // 4. Remove SSR Strategy + { + contract: cVault, + signature: "removeStrategy(address)", + args: [cSSRStrategyProxy.address], + }, + // 5. Remove USDT + { + contract: cVault, + signature: "removeAsset(address)", + args: [addresses.mainnet.USDT], + }, + // 6. Remove USDS + { + contract: cVault, + signature: "removeAsset(address)", + args: [addresses.mainnet.USDS], + }, + ], + }; + } +); From b3b7ae76ab721673badfe99b33c798b4a084fc90 Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:30:24 +0400 Subject: [PATCH 2/2] Fix fork tests --- contracts/deploy/mainnet/150_vault_upgrade.js | 1 + .../ousd-maker-ssr.mainnet.fork-test.js | 346 ---------------- ...o-guantlet-prime-usdt.mainnet.fork-test.js | 378 ------------------ .../test/vault/vault.mainnet.fork-test.js | 178 ++------- 4 files changed, 35 insertions(+), 868 deletions(-) delete mode 100644 contracts/test/strategies/ousd-maker-ssr.mainnet.fork-test.js delete mode 100644 contracts/test/strategies/ousd-morpho-guantlet-prime-usdt.mainnet.fork-test.js diff --git a/contracts/deploy/mainnet/150_vault_upgrade.js b/contracts/deploy/mainnet/150_vault_upgrade.js index 2bb3c2e2f4..55679d00c0 100644 --- a/contracts/deploy/mainnet/150_vault_upgrade.js +++ b/contracts/deploy/mainnet/150_vault_upgrade.js @@ -7,6 +7,7 @@ const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { deployName: "150_vault_upgrade", + forceSkip: true, //proposalId: "", }, async ({ ethers }) => { diff --git a/contracts/test/strategies/ousd-maker-ssr.mainnet.fork-test.js b/contracts/test/strategies/ousd-maker-ssr.mainnet.fork-test.js deleted file mode 100644 index bf4b834836..0000000000 --- a/contracts/test/strategies/ousd-maker-ssr.mainnet.fork-test.js +++ /dev/null @@ -1,346 +0,0 @@ -const { expect } = require("chai"); -const { formatUnits, parseUnits } = require("ethers/lib/utils"); - -const addresses = require("../../utils/addresses"); -const { units, isCI } = require("../helpers"); - -const { createFixtureLoader, makerSSRFixture } = require("../_fixture"); - -const log = require("../../utils/logger")("test:fork:ousd:makerSSR"); - -describe("ForkTest: Maker SSR Strategy", function () { - this.timeout(0); - - // Retry up to 3 times on CI - this.retries(isCI ? 3 : 0); - - let fixture; - - describe("post deployment", () => { - const loadFixture = createFixtureLoader(makerSSRFixture); - beforeEach(async () => { - fixture = await loadFixture(); - }); - it("Should have constants and immutables set", async () => { - const { vault, makerSSRStrategy } = fixture; - - expect(await makerSSRStrategy.platformAddress()).to.equal( - addresses.mainnet.sUSDS - ); - expect(await makerSSRStrategy.vaultAddress()).to.equal(vault.address); - expect(await makerSSRStrategy.shareToken()).to.equal( - addresses.mainnet.sUSDS - ); - expect(await makerSSRStrategy.assetToken()).to.equal( - addresses.mainnet.USDS - ); - expect( - await makerSSRStrategy.supportsAsset(addresses.mainnet.USDS) - ).to.equal(true); - expect( - await makerSSRStrategy.assetToPToken(addresses.mainnet.USDS) - ).to.equal(addresses.mainnet.sUSDS); - expect(await makerSSRStrategy.governor()).to.equal( - addresses.mainnet.Timelock - ); - }); - it("Should be able to check balance", async () => { - const { usds, josh, makerSSRStrategy } = fixture; - - // This uses a transaction to call a view function so the gas usage can be reported. - const tx = await makerSSRStrategy - .connect(josh) - .populateTransaction.checkBalance(usds.address); - await josh.sendTransaction(tx); - }); - it("Only Governor can approve all tokens", async () => { - const { - timelock, - oldTimelock, - strategist, - josh, - daniel, - domen, - vaultSigner, - makerSSRStrategy, - usds, - sUSDS, - } = fixture; - - // Governor can approve all tokens - const tx = await makerSSRStrategy - .connect(timelock) - .safeApproveAllTokens(); - await expect(tx).to.not.emit(sUSDS, "Approval"); - await expect(tx).to.emit(usds, "Approval"); - - for (const signer of [ - daniel, - domen, - josh, - strategist, - oldTimelock, - vaultSigner, - ]) { - const tx = makerSSRStrategy.connect(signer).safeApproveAllTokens(); - await expect(tx).to.be.revertedWith("Caller is not the Governor"); - } - }); - }); - - describe("with some USDS in the vault", () => { - const loadFixture = createFixtureLoader(makerSSRFixture, { - usdsMintAmount: 12000, - depositToStrategy: false, - }); - beforeEach(async () => { - fixture = await loadFixture(); - }); - it("Vault should deposit some USDS to strategy", async function () { - const { - usds, - ousd, - sUSDS, - makerSSRStrategy, - vault, - strategist, - vaultSigner, - } = fixture; - - const usdsDepositAmount = await units("1000", usds); - - // Vault transfers USDS to strategy - await usds - .connect(vaultSigner) - .transfer(makerSSRStrategy.address, usdsDepositAmount); - - await vault.connect(strategist).rebase(); - - const ousdSupplyBefore = await ousd.totalSupply(); - - log( - `Before depositing ${formatUnits( - usdsDepositAmount - )} USDS to Maker SSR Strategy` - ); - - const tx = await makerSSRStrategy - .connect(vaultSigner) - .deposit(usds.address, usdsDepositAmount); - - log(`After depositing USDS to Maker SSR Strategy`); - - // Check emitted event - await expect(tx) - .to.emit(makerSSRStrategy, "Deposit") - .withArgs(usds.address, sUSDS.address, usdsDepositAmount); - - // Check the OUSD total supply increase - const ousdSupplyAfter = await ousd.totalSupply(); - expect(ousdSupplyAfter).to.approxEqualTolerance( - ousdSupplyBefore.add(usdsDepositAmount), - 0.1 // 0.1% or 10 basis point - ); - }); - it("Only vault can deposit some USDS to the strategy", async function () { - const { - usds, - makerSSRStrategy, - vaultSigner, - strategist, - timelock, - oldTimelock, - josh, - } = fixture; - - const depositAmount = await units("50", usds); - await usds - .connect(vaultSigner) - .transfer(makerSSRStrategy.address, depositAmount); - - for (const signer of [strategist, oldTimelock, timelock, josh]) { - const tx = makerSSRStrategy - .connect(signer) - .deposit(usds.address, depositAmount); - - await expect(tx).to.revertedWith("Caller is not the Vault"); - } - }); - it("Only vault can deposit all USDS to strategy", async function () { - const { - usds, - makerSSRStrategy, - vaultSigner, - strategist, - oldTimelock, - timelock, - josh, - } = fixture; - - const depositAmount = await units("50", usds); - await usds - .connect(vaultSigner) - .transfer(makerSSRStrategy.address, depositAmount); - - for (const signer of [strategist, oldTimelock, timelock, josh]) { - const tx = makerSSRStrategy.connect(signer).depositAll(); - - await expect(tx).to.revertedWith("Caller is not the Vault"); - } - - const tx = await makerSSRStrategy.connect(vaultSigner).depositAll(); - await expect(tx).to.emit(makerSSRStrategy, "Deposit"); - }); - }); - - describe("with the strategy having some USDS in Maker SSR Strategy", () => { - const loadFixture = createFixtureLoader(makerSSRFixture, { - usdsMintAmount: 12000, - depositToStrategy: true, - }); - beforeEach(async () => { - fixture = await loadFixture(); - }); - it("Vault should be able to withdraw all", async () => { - const { usds, sUSDS, makerSSRStrategy, ousd, vault, vaultSigner } = - fixture; - - const usdsWithdrawAmountExpected = await sUSDS.maxWithdraw( - makerSSRStrategy.address - ); - log( - `Expected to withdraw ${formatUnits(usdsWithdrawAmountExpected)} USDS` - ); - - const ousdSupplyBefore = await ousd.totalSupply(); - const vaultUsdsBalanceBefore = await usds.balanceOf(vault.address); - - log("Before withdraw all from strategy"); - - // Now try to withdraw all the WETH from the strategy - const tx = await makerSSRStrategy.connect(vaultSigner).withdrawAll(); - - log("After withdraw all from strategy"); - - // Check emitted event - await expect(tx).to.emittedEvent("Withdrawal", [ - usds.address, - sUSDS.address, - (amount) => - expect(amount).approxEqualTolerance( - usdsWithdrawAmountExpected, - 0.01, - "Withdrawal amount" - ), - ]); - - const receipt = await tx.wait(); - const event = receipt.events?.find((e) => e.event === "Withdrawal"); - log(`Actual withdrawal amount: ${formatUnits(event.args[2])}`); - expect(event.args[2]).to.approxEqualTolerance( - usdsWithdrawAmountExpected, - 0.01 - ); - - // Check the OUSD total supply stays the same - expect(await ousd.totalSupply()).to.approxEqualTolerance( - ousdSupplyBefore, - 0.01 // 0.01% or 1 basis point - ); - - // Check the USDS amount in the vault increases - expect(await usds.balanceOf(vault.address)).to.approxEqualTolerance( - vaultUsdsBalanceBefore.add(usdsWithdrawAmountExpected), - 0.01 - ); - }); - it("Vault should be able to withdraw some USDS", async () => { - const { usds, sUSDS, makerSSRStrategy, ousd, vault, vaultSigner } = - fixture; - - const withdrawAmount = await units("1000", usds); - - const ousdSupplyBefore = await ousd.totalSupply(); - const vaultUsdsBalanceBefore = await usds.balanceOf(vault.address); - - log(`Before withdraw of ${formatUnits(withdrawAmount)} from strategy`); - - // Now try to withdraw the USDS from the strategy - const tx = await makerSSRStrategy - .connect(vaultSigner) - .withdraw(vault.address, usds.address, withdrawAmount); - - log("After withdraw from strategy"); - - // Check emitted event - await expect(tx) - .to.emit(makerSSRStrategy, "Withdrawal") - .withArgs(usds.address, sUSDS.address, withdrawAmount); - - // Check the OUSD total supply stays the same - const ousdSupplyAfter = await ousd.totalSupply(); - expect(ousdSupplyAfter).to.approxEqualTolerance( - ousdSupplyBefore, - 0.01 // 0.01% or 1 basis point - ); - - // Check the USDS balance in the Vault - expect(await usds.balanceOf(vault.address)).to.equal( - vaultUsdsBalanceBefore.add(withdrawAmount) - ); - }); - it("Only vault can withdraw some USDS from AMO strategy", async function () { - const { - makerSSRStrategy, - oethVault, - strategist, - timelock, - oldTimelock, - josh, - weth, - } = fixture; - - for (const signer of [strategist, timelock, oldTimelock, josh]) { - const tx = makerSSRStrategy - .connect(signer) - .withdraw(oethVault.address, weth.address, parseUnits("50")); - - await expect(tx).to.revertedWith("Caller is not the Vault"); - } - }); - it("Only vault and governor can withdraw all USDS from Maker SSR strategy", async function () { - const { makerSSRStrategy, strategist, timelock, josh } = fixture; - - for (const signer of [strategist, josh]) { - const tx = makerSSRStrategy.connect(signer).withdrawAll(); - - await expect(tx).to.revertedWith("Caller is not the Vault or Governor"); - } - - // Governor can withdraw all - const tx = makerSSRStrategy.connect(timelock).withdrawAll(); - await expect(tx).to.emit(makerSSRStrategy, "Withdrawal"); - }); - }); - - describe("administration", () => { - const loadFixture = createFixtureLoader(makerSSRFixture); - beforeEach(async () => { - fixture = await loadFixture(); - }); - it("Governor should not be able to set the platform token", () => { - const { frxETH, sfrxETH, makerSSRStrategy, timelock } = fixture; - - const tx = makerSSRStrategy - .connect(timelock) - .setPTokenAddress(frxETH.address, sfrxETH.address); - expect(tx).to.be.revertedWith("unsupported function"); - }); - it("Governor should not be able to remove the platform token", () => { - const { makerSSRStrategy, timelock } = fixture; - - const tx = makerSSRStrategy.connect(timelock).removePToken(0); - expect(tx).to.be.revertedWith("unsupported function"); - }); - }); -}); diff --git a/contracts/test/strategies/ousd-morpho-guantlet-prime-usdt.mainnet.fork-test.js b/contracts/test/strategies/ousd-morpho-guantlet-prime-usdt.mainnet.fork-test.js deleted file mode 100644 index c2d401f1c5..0000000000 --- a/contracts/test/strategies/ousd-morpho-guantlet-prime-usdt.mainnet.fork-test.js +++ /dev/null @@ -1,378 +0,0 @@ -const { expect } = require("chai"); -const { formatUnits, parseUnits } = require("ethers/lib/utils"); - -const addresses = require("../../utils/addresses"); -const { units, isCI } = require("../helpers"); - -const { - createFixtureLoader, - morphoGauntletPrimeUSDTFixture, -} = require("../_fixture"); - -const log = require("../../utils/logger"); - -describe("ForkTest: Morpho Gauntlet Prime USDT Strategy", function () { - this.timeout(0); - - // Retry up to 3 times on CI - this.retries(isCI ? 3 : 0); - - let fixture; - - describe("post deployment", () => { - const loadFixture = createFixtureLoader(morphoGauntletPrimeUSDTFixture); - beforeEach(async () => { - fixture = await loadFixture(); - }); - it("Should have constants and immutables set", async () => { - const { vault, morphoGauntletPrimeUSDTStrategy } = fixture; - - expect(await morphoGauntletPrimeUSDTStrategy.platformAddress()).to.equal( - addresses.mainnet.MorphoGauntletPrimeUSDTVault - ); - expect(await morphoGauntletPrimeUSDTStrategy.vaultAddress()).to.equal( - vault.address - ); - expect(await morphoGauntletPrimeUSDTStrategy.shareToken()).to.equal( - addresses.mainnet.MorphoGauntletPrimeUSDTVault - ); - expect(await morphoGauntletPrimeUSDTStrategy.assetToken()).to.equal( - addresses.mainnet.USDT - ); - expect( - await morphoGauntletPrimeUSDTStrategy.supportsAsset( - addresses.mainnet.USDT - ) - ).to.equal(true); - expect( - await morphoGauntletPrimeUSDTStrategy.assetToPToken( - addresses.mainnet.USDT - ) - ).to.equal(addresses.mainnet.MorphoGauntletPrimeUSDTVault); - expect(await morphoGauntletPrimeUSDTStrategy.governor()).to.equal( - addresses.mainnet.Timelock - ); - expect(await vault.getAllStrategies()).to.include( - morphoGauntletPrimeUSDTStrategy.address - ); - }); - it("Should be able to check balance", async () => { - const { usdt, josh, morphoGauntletPrimeUSDTStrategy } = fixture; - - // This uses a transaction to call a view function so the gas usage can be reported. - const tx = await morphoGauntletPrimeUSDTStrategy - .connect(josh) - .populateTransaction.checkBalance(usdt.address); - await josh.sendTransaction(tx); - }); - it("Only Governor can approve all tokens", async () => { - const { - oldTimelock, - strategist, - josh, - daniel, - domen, - morphoGauntletPrimeUSDTStrategy, - vaultSigner, - } = fixture; - - for (const signer of [ - daniel, - domen, - josh, - strategist, - oldTimelock, - vaultSigner, - ]) { - const tx = morphoGauntletPrimeUSDTStrategy - .connect(signer) - .safeApproveAllTokens(); - await expect(tx).to.be.revertedWith("Caller is not the Governor"); - } - }); - }); - - describe("with some USDT in the vault", () => { - const loadFixture = createFixtureLoader(morphoGauntletPrimeUSDTFixture, { - usdtMintAmount: 12000, - depositToStrategy: false, - }); - beforeEach(async () => { - fixture = await loadFixture(); - }); - - it("Vault should deposit some USDT to strategy", async function () { - const { - usdt, - ousd, - morphoGauntletPrimeUSDTStrategy, - vault, - strategist, - vaultSigner, - } = fixture; - - const checkBalanceBefore = - await morphoGauntletPrimeUSDTStrategy.checkBalance(usdt.address); - - const usdtDepositAmount = await units("1000", usdt); - - // Vault transfers USDT to strategy - await usdt - .connect(vaultSigner) - .transfer(morphoGauntletPrimeUSDTStrategy.address, usdtDepositAmount); - - await vault.connect(strategist).rebase(); - - const ousdSupplyBefore = await ousd.totalSupply(); - - const tx = await morphoGauntletPrimeUSDTStrategy - .connect(vaultSigner) - .deposit(usdt.address, usdtDepositAmount); - - // Check emitted event - await expect(tx) - .to.emit(morphoGauntletPrimeUSDTStrategy, "Deposit") - .withArgs( - usdt.address, - addresses.mainnet.MorphoGauntletPrimeUSDTVault, - usdtDepositAmount - ); - - // Check the OUSD total supply increase - const ousdSupplyAfter = await ousd.totalSupply(); - expect(ousdSupplyAfter).to.approxEqualTolerance( - ousdSupplyBefore.add(usdtDepositAmount), - 0.1 // 0.1% or 10 basis point - ); - expect( - await morphoGauntletPrimeUSDTStrategy.checkBalance(usdt.address) - ).to.approxEqualTolerance( - checkBalanceBefore.add(usdtDepositAmount), - 0.01 - ); // 0.01% or 1 basis point - }); - it("Only vault can deposit some USDT to the strategy", async function () { - const { - usdt, - morphoGauntletPrimeUSDTStrategy, - vaultSigner, - strategist, - timelock, - oldTimelock, - josh, - } = fixture; - - const depositAmount = await units("50", usdt); - await usdt - .connect(vaultSigner) - .transfer(morphoGauntletPrimeUSDTStrategy.address, depositAmount); - - for (const signer of [strategist, oldTimelock, timelock, josh]) { - const tx = morphoGauntletPrimeUSDTStrategy - .connect(signer) - .deposit(usdt.address, depositAmount); - - await expect(tx).to.revertedWith("Caller is not the Vault"); - } - }); - it("Only vault can deposit all USDT to strategy", async function () { - const { - usdt, - morphoGauntletPrimeUSDTStrategy, - vaultSigner, - strategist, - timelock, - oldTimelock, - josh, - } = fixture; - - const depositAmount = await units("50", usdt); - await usdt - .connect(vaultSigner) - .transfer(morphoGauntletPrimeUSDTStrategy.address, depositAmount); - - for (const signer of [strategist, oldTimelock, timelock, josh]) { - const tx = morphoGauntletPrimeUSDTStrategy.connect(signer).depositAll(); - - await expect(tx).to.revertedWith("Caller is not the Vault"); - } - - const tx = await morphoGauntletPrimeUSDTStrategy - .connect(vaultSigner) - .depositAll(); - await expect(tx).to.emit(morphoGauntletPrimeUSDTStrategy, "Deposit"); - }); - }); - - describe("with the strategy having some USDT", () => { - const loadFixture = createFixtureLoader(morphoGauntletPrimeUSDTFixture, { - usdtMintAmount: 12000, - depositToStrategy: true, - }); - beforeEach(async () => { - fixture = await loadFixture(); - }); - - it("Vault should be able to withdraw all", async () => { - const { - usdt, - morphoGauntletPrimeUSDTVault, - morphoGauntletPrimeUSDTStrategy, - ousd, - vault, - vaultSigner, - } = fixture; - - const usdtWithdrawAmountExpected = - await morphoGauntletPrimeUSDTVault.maxWithdraw( - morphoGauntletPrimeUSDTStrategy.address - ); - - log( - `Expected to withdraw ${formatUnits(usdtWithdrawAmountExpected)} USDT` - ); - - const ousdSupplyBefore = await ousd.totalSupply(); - const vaultUSDTBalanceBefore = await usdt.balanceOf(vault.address); - - log("Before withdraw all from strategy"); - - // Now try to withdraw all the WETH from the strategy - const tx = await morphoGauntletPrimeUSDTStrategy - .connect(vaultSigner) - .withdrawAll(); - - log("After withdraw all from strategy"); - - // Check emitted event - await expect(tx).to.emittedEvent("Withdrawal", [ - usdt.address, - morphoGauntletPrimeUSDTVault.address, - (amount) => - expect(amount).approxEqualTolerance( - usdtWithdrawAmountExpected, - 0.01, - "Withdrawal amount" - ), - ]); - - // Check the OUSD total supply stays the same - expect(await ousd.totalSupply()).to.approxEqualTolerance( - ousdSupplyBefore, - 0.01 // 0.01% or 1 basis point - ); - - // Check the USDT amount in the vault increases - expect(await usdt.balanceOf(vault.address)).to.approxEqualTolerance( - vaultUSDTBalanceBefore.add(usdtWithdrawAmountExpected), - 0.01 - ); - }); - it("Vault should be able to withdraw some USDT", async () => { - const { - usdt, - morphoGauntletPrimeUSDTVault, - morphoGauntletPrimeUSDTStrategy, - ousd, - vault, - vaultSigner, - } = fixture; - - const withdrawAmount = await units("1000", usdt); - - const ousdSupplyBefore = await ousd.totalSupply(); - const vaultUSDTBalanceBefore = await usdt.balanceOf(vault.address); - - log(`Before withdraw of ${formatUnits(withdrawAmount)} from strategy`); - - // Now try to withdraw the USDT from the strategy - const tx = await morphoGauntletPrimeUSDTStrategy - .connect(vaultSigner) - .withdraw(vault.address, usdt.address, withdrawAmount); - - log("After withdraw from strategy"); - - // Check emitted event - await expect(tx) - .to.emit(morphoGauntletPrimeUSDTStrategy, "Withdrawal") - .withArgs( - usdt.address, - morphoGauntletPrimeUSDTVault.address, - withdrawAmount - ); - - // Check the OUSD total supply stays the same - const ousdSupplyAfter = await ousd.totalSupply(); - expect(ousdSupplyAfter).to.approxEqualTolerance( - ousdSupplyBefore, - 0.01 // 0.01% or 1 basis point - ); - - // Check the USDT balance in the Vault - expect(await usdt.balanceOf(vault.address)).to.equal( - vaultUSDTBalanceBefore.add(withdrawAmount) - ); - }); - it("Only vault can withdraw some USDT from strategy", async function () { - const { - morphoGauntletPrimeUSDTStrategy, - oethVault, - strategist, - timelock, - oldTimelock, - josh, - weth, - } = fixture; - - for (const signer of [strategist, timelock, oldTimelock, josh]) { - const tx = morphoGauntletPrimeUSDTStrategy - .connect(signer) - .withdraw(oethVault.address, weth.address, parseUnits("50")); - - await expect(tx).to.revertedWith("Caller is not the Vault"); - } - }); - it("Only vault and governor can withdraw all USDT from Maker DSR strategy", async function () { - const { morphoGauntletPrimeUSDTStrategy, strategist, timelock, josh } = - fixture; - - for (const signer of [strategist, josh]) { - const tx = morphoGauntletPrimeUSDTStrategy - .connect(signer) - .withdrawAll(); - - await expect(tx).to.revertedWith("Caller is not the Vault or Governor"); - } - - // Governor can withdraw all - const tx = morphoGauntletPrimeUSDTStrategy - .connect(timelock) - .withdrawAll(); - await expect(tx).to.emit(morphoGauntletPrimeUSDTStrategy, "Withdrawal"); - }); - }); - - describe("administration", () => { - const loadFixture = createFixtureLoader(morphoGauntletPrimeUSDTFixture); - beforeEach(async () => { - fixture = await loadFixture(); - }); - it("Governor should not be able to set the platform token", () => { - const { frxETH, sfrxETH, morphoGauntletPrimeUSDTStrategy, timelock } = - fixture; - - const tx = morphoGauntletPrimeUSDTStrategy - .connect(timelock) - .setPTokenAddress(frxETH.address, sfrxETH.address); - expect(tx).to.be.revertedWith("unsupported function"); - }); - it("Governor should not be able to remove the platform token", () => { - const { morphoGauntletPrimeUSDTStrategy, timelock } = fixture; - - const tx = morphoGauntletPrimeUSDTStrategy - .connect(timelock) - .removePToken(0); - expect(tx).to.be.revertedWith("unsupported function"); - }); - }); -}); diff --git a/contracts/test/vault/vault.mainnet.fork-test.js b/contracts/test/vault/vault.mainnet.fork-test.js index 0c6e6e3c02..a1c8b12b3d 100644 --- a/contracts/test/vault/vault.mainnet.fork-test.js +++ b/contracts/test/vault/vault.mainnet.fork-test.js @@ -5,9 +5,7 @@ const addresses = require("../../utils/addresses"); const { loadDefaultFixture } = require("./../_fixture"); const { ousdUnits, - usdtUnits, usdcUnits, - usdsUnits, differenceInStrategyBalance, differenceInErc20TokenBalances, isCI, @@ -55,14 +53,12 @@ describe("ForkTest: Vault", function () { await josh.sendTransaction(tx); }); it("Should check asset balances", async () => { - const { usds, usdc, usdt, josh, vault } = fixture; + const { usdc, josh, vault } = fixture; - for (const asset of [usds, usdc, usdt]) { - const tx = await vault - .connect(josh) - .populateTransaction.checkBalance(asset.address); - await josh.sendTransaction(tx); - } + const tx = await vault + .connect(josh) + .populateTransaction.checkBalance(usdc.address); + await josh.sendTransaction(tx); }); }); @@ -89,14 +85,9 @@ describe("ForkTest: Vault", function () { it("Should have supported assets", async () => { const { vault } = fixture; const assets = await vault.getAllAssets(); - expect(assets).to.have.length(3); - expect(assets).to.include(addresses.mainnet.USDT); + expect(assets).to.have.length(1); expect(assets).to.include(addresses.mainnet.USDC); - expect(assets).to.include(addresses.mainnet.USDS); - - expect(await vault.isSupportedAsset(addresses.mainnet.USDT)).to.be.true; expect(await vault.isSupportedAsset(addresses.mainnet.USDC)).to.be.true; - expect(await vault.isSupportedAsset(addresses.mainnet.USDS)).to.be.true; }); }); @@ -118,28 +109,6 @@ describe("ForkTest: Vault", function () { expect(await vault.capitalPaused()).to.be.false; }); - it("Should allow to mint and redeem w/ USDT", async () => { - const { ousd, vault, josh, usdt } = fixture; - const balancePreMint = await ousd - .connect(josh) - .balanceOf(josh.getAddress()); - await vault.connect(josh).mint(usdt.address, usdtUnits("500"), 0); - - const balancePostMint = await ousd - .connect(josh) - .balanceOf(josh.getAddress()); - - const balanceDiff = balancePostMint.sub(balancePreMint); - expect(balanceDiff).to.approxEqualTolerance(ousdUnits("500"), 1); - - await vault.connect(josh).redeem(balanceDiff, 0); - - const balancePostRedeem = await ousd - .connect(josh) - .balanceOf(josh.getAddress()); - expect(balancePreMint).to.approxEqualTolerance(balancePostRedeem, 1); - }); - it("Should allow to mint and redeem w/ USDC", async () => { const { ousd, vault, josh, usdc } = fixture; const balancePreMint = await ousd @@ -162,32 +131,10 @@ describe("ForkTest: Vault", function () { expect(balancePreMint).to.approxEqualTolerance(balancePostRedeem, 1); }); - it("Should allow to mint and redeem w/ USDS", async () => { - const { ousd, vault, josh, usds } = fixture; - const balancePreMint = await ousd - .connect(josh) - .balanceOf(josh.getAddress()); - await vault.connect(josh).mint(usds.address, usdsUnits("500"), 0); - - const balancePostMint = await ousd - .connect(josh) - .balanceOf(josh.getAddress()); - - const balanceDiff = balancePostMint.sub(balancePreMint); - expect(balanceDiff).to.approxEqualTolerance(ousdUnits("500"), 1); - - await vault.connect(josh).redeem(balanceDiff, 0); - - const balancePostRedeem = await ousd - .connect(josh) - .balanceOf(josh.getAddress()); - expect(balancePreMint).to.approxEqualTolerance(balancePostRedeem, 1); - }); - it("Should calculate and return redeem outputs", async () => { const { vault } = fixture; const outputs = await vault.calculateRedeemOutputs(ousdUnits("100")); - expect(outputs).to.have.length(3); + expect(outputs).to.have.length(1); const assets = await vault.getAllAssets(); const values = await Promise.all( @@ -202,67 +149,68 @@ describe("ForkTest: Vault", function () { }) ); - expect( - ousdUnits((values[0] + values[1] + values[2]).toString()) - ).to.approxEqualTolerance(ousdUnits("100"), 0.5); + expect(ousdUnits(values[0].toString())).to.approxEqualTolerance( + ousdUnits("100"), + 0.5 + ); }); it("should withdraw from and deposit to strategy", async () => { - const { vault, josh, usdt, morphoGauntletPrimeUSDTStrategy } = fixture; - await vault.connect(josh).mint(usdt.address, usdtUnits("90"), 0); + const { vault, josh, usdc, morphoGauntletPrimeUSDCStrategy } = fixture; + await vault.connect(josh).mint(usdc.address, usdcUnits("90"), 0); const strategistSigner = await impersonateAndFund( await vault.strategistAddr() ); - let usdtBalanceDiff, usdtStratDiff; + let usdcBalanceDiff, usdcStratDiff; - [usdtBalanceDiff] = await differenceInErc20TokenBalances( + [usdcBalanceDiff] = await differenceInErc20TokenBalances( [vault.address], - [usdt], + [usdc], async () => { - [usdtStratDiff] = await differenceInStrategyBalance( - [usdt.address], - [morphoGauntletPrimeUSDTStrategy], + [usdcStratDiff] = await differenceInStrategyBalance( + [usdc.address], + [morphoGauntletPrimeUSDCStrategy], async () => { await vault .connect(strategistSigner) .depositToStrategy( - morphoGauntletPrimeUSDTStrategy.address, - [usdt.address], - [usdtUnits("90")] + morphoGauntletPrimeUSDCStrategy.address, + [usdc.address], + [usdcUnits("90")] ); } ); } ); - expect(usdtBalanceDiff).to.equal(usdtUnits("-90")); + expect(usdcBalanceDiff).to.equal(usdcUnits("-90")); - expect(usdtStratDiff).gte(usdtUnits("89.91")); + expect(usdcStratDiff).gte(usdcUnits("89.91")); - [usdtBalanceDiff] = await differenceInErc20TokenBalances( + [usdcBalanceDiff] = await differenceInErc20TokenBalances( [vault.address], - [usdt], + [usdc], async () => { - [usdtStratDiff] = await differenceInStrategyBalance( - [usdt.address], - [morphoGauntletPrimeUSDTStrategy], + [usdcStratDiff] = await differenceInStrategyBalance( + [usdc.address], + [morphoGauntletPrimeUSDCStrategy], async () => { await vault .connect(strategistSigner) .withdrawFromStrategy( - morphoGauntletPrimeUSDTStrategy.address, - [usdt.address], - [usdtUnits("90")] + morphoGauntletPrimeUSDCStrategy.address, + [usdc.address], + [usdcUnits("90")] ); } ); } ); - expect(usdtBalanceDiff).to.equal(usdtUnits("90")); + expect(usdcBalanceDiff).to.equal(usdcUnits("90")); - expect(usdtStratDiff).to.lte(usdtUnits("-89.91")); + expect(usdcStratDiff).to.lte(usdcUnits("-89.91")); }); it("Should have vault buffer disabled", async () => { @@ -279,26 +227,6 @@ describe("ForkTest: Vault", function () { ); }); - it("Should return a price for minting with USDT", async () => { - const { vault, usdt } = fixture; - const price = await vault.priceUnitMint(usdt.address); - - log(`Price for minting with USDT: ${utils.formatEther(price, 6)}`); - - expect(price).to.be.lte(utils.parseEther("1")); - expect(price).to.be.gt(utils.parseEther("0.998")); - }); - - it("Should return a price for minting with USDS", async () => { - const { vault, usds } = fixture; - const price = await vault.priceUnitMint(usds.address); - - log(`Price for minting with USDS: ${utils.formatEther(price, 18)}`); - - expect(price).to.be.lte(utils.parseEther("1")); - expect(price).to.be.gt(utils.parseEther("0.999")); - }); - it("Should return a price for minting with USDC", async () => { const { vault, usdc } = fixture; const price = await vault.priceUnitMint(usdc.address); @@ -309,24 +237,6 @@ describe("ForkTest: Vault", function () { expect(price).to.be.gt(utils.parseEther("0.999")); }); - it("Should return a price for redeem with USDT", async () => { - const { vault, usdt } = fixture; - const price = await vault.priceUnitRedeem(usdt.address); - - log(`Price for redeeming with USDT: ${utils.formatEther(price, 6)}`); - - expect(price).to.be.gte(utils.parseEther("1")); - }); - - it("Should return a price for redeem with USDS", async () => { - const { vault, usds } = fixture; - const price = await vault.priceUnitRedeem(usds.address); - - log(`Price for redeeming with USDS: ${utils.formatEther(price, 18)}`); - - expect(price).to.be.gte(utils.parseEther("1")); - }); - it("Should return a price for redeem with USDC", async () => { const { vault, usdc } = fixture; const price = await vault.priceUnitRedeem(usdc.address); @@ -344,8 +254,6 @@ describe("ForkTest: Vault", function () { const knownAssets = [ // TODO: Update this every time a new asset is supported - "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT - "0xdC035D45d973E3EC169d2276DDab16f1e407384F", // USDS "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC ]; @@ -364,10 +272,8 @@ describe("ForkTest: Vault", function () { const knownStrategies = [ // Update this every time a new strategy is added. Below are mainnet addresses - "0x5Bd9AF9c2506D29B6d79cB878284A270190EaEAa", // Maker SSR Strategy "0x603CDEAEC82A60E3C4A10dA6ab546459E5f64Fa0", // Meta Morpho USDC "0x2B8f37893EE713A4E9fF0cEb79F27539f20a32a1", // Morpho Gauntlet Prime USDC - "0xe3ae7C80a1B02Ccd3FB0227773553AEB14e32F26", // Morpho Gauntlet Prime USDT "0x26a02ec47ACC2A3442b757F45E0A82B8e993Ce11", // Curve AMO OUSD/USDC ]; @@ -386,14 +292,6 @@ describe("ForkTest: Vault", function () { } }); - it("Should have correct default strategy set for USDT", async () => { - const { vault, usdt } = fixture; - - expect([ - "0xe3ae7C80a1B02Ccd3FB0227773553AEB14e32F26", // Morpho Gauntlet Prime USDT - ]).to.include(await vault.assetDefaultStrategies(usdt.address)); - }); - it("Should have correct default strategy set for USDC", async () => { const { vault, usdc } = fixture; @@ -402,14 +300,6 @@ describe("ForkTest: Vault", function () { ]).to.include(await vault.assetDefaultStrategies(usdc.address)); }); - it("Should have correct default strategy set for USDS", async () => { - const { vault, usds } = fixture; - - expect([ - "0x5Bd9AF9c2506D29B6d79cB878284A270190EaEAa", // Maker SSR Strategy - ]).to.include(await vault.assetDefaultStrategies(usds.address)); - }); - it("Should be able to withdraw from all strategies", async () => { const { vault, timelock } = fixture; await vault.connect(timelock).withdrawAllFromStrategies();