diff --git a/contracts/contracts/proxies/Proxies.sol b/contracts/contracts/proxies/Proxies.sol index 39f70cec94..0677a7dbcd 100644 --- a/contracts/contracts/proxies/Proxies.sol +++ b/contracts/contracts/proxies/Proxies.sol @@ -244,7 +244,7 @@ contract OUSDMorphoV2StrategyProxy is InitializeGovernedUpgradeabilityProxy { } /** - * @notice OETHSupernovaAMOProxy delegates calls to an OETHSupernovaAMOStrategy implementation + * @notice Legacy Supernova AMO proxy */ contract OETHSupernovaAMOProxy is InitializeGovernedUpgradeabilityProxy { diff --git a/contracts/contracts/strategies/algebra/OETHSupernovaAMOStrategy.sol b/contracts/contracts/strategies/algebra/OETHSupernovaAMOStrategy.sol deleted file mode 100644 index 04eccabf7d..0000000000 --- a/contracts/contracts/strategies/algebra/OETHSupernovaAMOStrategy.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.0; - -/** - * @title Supernova OETH Algorithmic Market Maker (AMO) Strategy - * @notice AMO strategy for the Supernova OETH/WETH stable pool - * @author Origin Protocol Inc - */ -import { StableSwapAMMStrategy } from "./StableSwapAMMStrategy.sol"; -import { IGauge } from "../../interfaces/algebra/IAlgebraGauge.sol"; - -contract OETHSupernovaAMOStrategy is StableSwapAMMStrategy { - /** - * @param _baseConfig The `platformAddress` is the address of the Supernova OETH/WETH pool. - * The `vaultAddress` is the address of the OETH Vault. - * @param _gauge Address of the Supernova gauge for the pool. - */ - constructor(BaseStrategyConfig memory _baseConfig, address _gauge) - StableSwapAMMStrategy(_baseConfig, _gauge, IGauge(_gauge).TOKEN()) - {} -} diff --git a/contracts/contracts/strategies/algebra/README.md b/contracts/contracts/strategies/algebra/README.md deleted file mode 100644 index 2d0dc5066c..0000000000 --- a/contracts/contracts/strategies/algebra/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Diagrams - -## OETH Supernova AMO Strategy - -### Hierarchy - -![OETH Supernova AMO Strategy Hierarchy](../../../docs/OETHSupernovaAMOStrategyHierarchy.svg) - -### Interactions - -![OETH Supernova AMO Strategy Interactions](../../../docs/OETHSupernovaAMOStrategyInteractions.svg) - -### Squashed - -![OETH Supernova AMO Strategy Squashed](../../../docs/OETHSupernovaAMOStrategySquashed.svg) - -### Storage - -![OETH Supernova AMO Strategy Storage](../../../docs/OETHSupernovaAMOStrategyStorage.svg) diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 00edb61211..c4cef69840 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -857,49 +857,6 @@ const deploySonicSwapXAMOStrategyImplementationAndInitialize = async () => { return cSonicSwapXAMOStrategy; }; -const deployOETHSupernovaAMOStrategyImplementation = async () => { - const { deployerAddr } = await getNamedAccounts(); - const sDeployer = await ethers.provider.getSigner(deployerAddr); - - const cOETHSupernovaAMOStrategyProxy = await ethers.getContract( - "OETHSupernovaAMOProxy" - ); - const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); - - // Deploy OETH Supernova AMO Strategy implementation that will serve - // OETH Supernova AMO - const dSupernovaAMOStrategy = await deployWithConfirmation( - "OETHSupernovaAMOStrategy", - [ - [addresses.mainnet.SupernovaOETHWETH.pool, cOETHVaultProxy.address], - addresses.mainnet.SupernovaOETHWETH.gauge, - ] - ); - - const cOETHSupernovaAMOStrategy = await ethers.getContractAt( - "OETHSupernovaAMOStrategy", - cOETHSupernovaAMOStrategyProxy.address - ); - - // Initialize OETH Supernova AMO Strategy implementation - const depositPriceRange = parseUnits("0.01", 18); // 1% or 100 basis points - const initData = cOETHSupernovaAMOStrategy.interface.encodeFunctionData( - "initialize(address[],uint256)", - [[addresses.mainnet.supernovaToken], depositPriceRange] - ); - await withConfirmation( - // prettier-ignore - cOETHSupernovaAMOStrategyProxy - .connect(sDeployer)["initialize(address,address,bytes)"]( - dSupernovaAMOStrategy.address, - addresses.mainnet.Timelock, - initData - ) - ); - - return cOETHSupernovaAMOStrategy; -}; - // Poll eth_getCode until bytecode appears at `addr`. Base's read replicas can // lag the sequencer by several seconds, so a fresh deploy receipt does not // guarantee that the next call's RPC node sees the contract yet. @@ -1343,7 +1300,6 @@ module.exports = { getPlumeContracts, deploySonicSwapXAMOStrategyImplementation, deploySonicSwapXAMOStrategyImplementationAndInitialize, - deployOETHSupernovaAMOStrategyImplementation, deployOETHbHydrexAMOStrategyImplementation, deployProxyWithCreateX, deployCrossChainMasterStrategyImpl, diff --git a/contracts/deploy/mainnet/180_vault_upgrade_supernova_AMO.js b/contracts/deploy/mainnet/180_vault_upgrade_supernova_AMO.js index 6b006662f5..4d447106ba 100644 --- a/contracts/deploy/mainnet/180_vault_upgrade_supernova_AMO.js +++ b/contracts/deploy/mainnet/180_vault_upgrade_supernova_AMO.js @@ -1,86 +1,19 @@ -const addresses = require("../../utils/addresses"); -const { - deploymentWithGovernanceProposal, - deployWithConfirmation, -} = require("../../utils/deploy"); -const { - deployOETHSupernovaAMOStrategyImplementation, -} = require("../deployActions"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { deployName: "180_vault_upgrade_supernova_AMO", forceDeploy: false, + forceSkip: true, reduceQueueTime: true, deployerIsProposer: false, proposalId: "16177445778432224472212272508299557275111595204509579362893638738519171283271", }, - async ({ ethers }) => { - // 1. Deploy new OETH Vault Core and Admin implementations - const dVaultAdmin = await deployWithConfirmation( - "OETHVault", - [addresses.mainnet.WETH], - undefined, - true - ); - - // 2. Connect to the OETH Vault as its governor via the proxy - const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); - const cVault = await ethers.getContractAt( - "IVault", - cOETHVaultProxy.address - ); - - // 3. Connect to the Compounding Staking Strategy Proxy to set it as default strategy - const defaultStrategy = await ethers.getContract( - "CompoundingStakingSSVStrategyProxy" - ); - - // 4. Deploy Supernova AMO Strategy implementation - await deployWithConfirmation("OETHSupernovaAMOProxy"); - const cOETHSupernovaAMOProxy = await ethers.getContract( - "OETHSupernovaAMOProxy" - ); - - // Deploy Supernova AMO Strategy implementation - const cSupernovaAMOStrategy = - await deployOETHSupernovaAMOStrategyImplementation(); - + async () => { return { name: "Upgrade OETH Vault to new Core and Admin implementations and deploy Supernova AMO Strategy", - actions: [ - // 1. Upgrade the OETH Vault proxy to the new core vault implementation - { - contract: cOETHVaultProxy, - signature: "upgradeTo(address)", - args: [dVaultAdmin.address], - }, - // 2. Set Compounding Staking Strategy as default strategy - { - contract: cVault, - signature: "setDefaultStrategy(address)", - args: [defaultStrategy.address], - }, - // 3. Approve new strategy on the Vault - { - contract: cVault, - signature: "approveStrategy(address)", - args: [cOETHSupernovaAMOProxy.address], - }, - // 4. Add strategy to mint whitelist - { - contract: cVault, - signature: "addStrategyToMintWhitelist(address)", - args: [cOETHSupernovaAMOProxy.address], - }, - // 5. Set the Harvester on the Supernova AMO strategy - { - contract: cSupernovaAMOStrategy, - signature: "setHarvesterAddress(address)", - args: [addresses.multichainStrategist], - }, - ], + actions: [], }; } ); diff --git a/contracts/deploy/mainnet/194_remove_oeth_supernova_amo.js b/contracts/deploy/mainnet/194_remove_oeth_supernova_amo.js new file mode 100644 index 0000000000..6d2cb19d4d --- /dev/null +++ b/contracts/deploy/mainnet/194_remove_oeth_supernova_amo.js @@ -0,0 +1,30 @@ +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "194_remove_oeth_supernova_amo", + forceDeploy: false, + reduceQueueTime: true, + deployerIsProposer: false, + proposalId: "35609681461618052145387081603214161093035331291961687423754678012941529359332", + }, + async ({ ethers }) => { + // Current OETH Vault contracts + const cVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); + const cStrategyProxy = await ethers.getContract("OETHSupernovaAMOProxy"); + + // Governance Actions + // ---------------- + return { + name: "Remove the Supernova AMO Strategy from the OETH Vault", + actions: [ + { + contract: cVault, + signature: "removeStrategy(address)", + args: [cStrategyProxy.address], + }, + ], + }; + } +); diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index ed4147e3c2..0943564e81 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -36,7 +36,6 @@ const merklDistributorAbi = require("./abi/merklDistributor.json"); const curveXChainLiquidityGaugeAbi = require("./abi/curveXChainLiquidityGauge.json"); const curveStableSwapNGAbi = require("./abi/curveStableSwapNG.json"); const { defaultAbiCoder, parseUnits } = require("ethers/lib/utils"); -const { formatUnits } = ethers.utils; const { impersonateAndFund } = require("../utils/signers"); const log = require("../utils/logger")("test:fixtures"); @@ -1317,168 +1316,6 @@ async function instantRebaseVaultFixture(tokenName) { return fixture; } -async function supernovaOETHAMOFixture( - config = { - assetMintAmount: 0, - depositToStrategy: false, - balancePool: false, - poolAddWethAmount: 0, - poolAddOethAmount: 0, - } -) { - const fixture = await defaultFixture(); - const { oeth, oethVault, weth, josh, strategist } = fixture; - - if (!isFork) { - throw new Error("supernovaOETHAMOFixture is only supported on fork tests"); - } - - const cfg = { - assetMintAmount: config?.assetMintAmount || 0, - depositToStrategy: config?.depositToStrategy || false, - balancePool: config?.balancePool || false, - poolAddWethAmount: config?.poolAddWethAmount || 0, - poolAddOethAmount: config?.poolAddOethAmount || 0, - }; - - const cOETHSupernovaAMOProxy = await ethers.getContract( - "OETHSupernovaAMOProxy" - ); - const cOETHSupernovaAMOStrategy = await ethers.getContractAt( - "OETHSupernovaAMOStrategy", - cOETHSupernovaAMOProxy.address - ); - - const supernovaPool = await ethers.getContractAt( - "IPair", - await cOETHSupernovaAMOStrategy.pool() - ); - const supernovaGauge = await ethers.getContractAt( - "IGauge", - await cOETHSupernovaAMOStrategy.gauge() - ); - const supernovaRewardToken = await ethers.getContractAt( - erc20Abi, - addresses.mainnet.supernovaToken - ); - - // Impersonate the OETH Vault to call strategy deposit/withdraw methods directly in tests. - const oethVaultSigner = await impersonateAndFund(oethVault.address); - const oethVaultGovernor = await impersonateAndFund( - await oethVault.governor() - ); - - // Ensure the test actor has enough WETH to mint OETH and manipulate pool balances. - await setERC20TokenBalance(josh.address, weth, oethUnits("1000000000"), hre); - await resetAllowance(weth, josh, oethVault.address); - - // Supernova deployment creates a fresh empty pool, seed it once for AMO tests. - let seedAmount = parseUnits("150"); - if ((await supernovaPool.totalSupply()).lt(seedAmount.mul(2))) { - await oethVault.connect(josh).mint(seedAmount.mul(2)); - await weth.connect(josh).transfer(supernovaPool.address, seedAmount); - await oeth.connect(josh).transfer(supernovaPool.address, seedAmount); - await supernovaPool.connect(josh).mint(josh.address); - } - - // Mint some OETH using WETH if configured. - if (cfg.assetMintAmount > 0) { - const wethAmount = parseUnits(cfg.assetMintAmount.toString()); - await oethVault.connect(oethVaultGovernor).rebase(); - await oethVault.connect(josh).allocate(); - - let wethBalance = await weth.balanceOf(oethVault.address); - const autoAllocateThreshold = await oethVault.autoAllocateThreshold(); - const queue = await oethVault.withdrawalQueueMetadata(); - const available = wethBalance.add(queue.claimed).sub(queue.queued); - const mintAmount = wethAmount.sub(available); - - if (mintAmount.gt(0)) { - await weth.connect(josh).approve(oethVault.address, mintAmount); - - const disableAutoAllocate = autoAllocateThreshold.lt(mintAmount); - if (disableAutoAllocate) { - await oethVault - .connect(oethVaultGovernor) - .setAutoAllocateThreshold(mintAmount.add(1)); - } - - // This mints OETH and keeps backing WETH in the vault. - await oethVault.connect(josh).mint(mintAmount); - - if (disableAutoAllocate) { - await oethVault - .connect(oethVaultGovernor) - .setAutoAllocateThreshold(autoAllocateThreshold); - } - } - - if (cfg.depositToStrategy) { - wethBalance = await weth.balanceOf(oethVault.address); - log( - `Depositing ${formatUnits( - wethAmount - )} WETH to Supernova AMO strategy. Vault has ${formatUnits( - wethBalance - )} WETH` - ); - await oethVault - .connect(strategist) - .depositToStrategy( - cOETHSupernovaAMOStrategy.address, - [weth.address], - [wethAmount] - ); - } - } - - if (cfg.balancePool) { - const { _reserve0, _reserve1 } = await supernovaPool.getReserves(); - const oTokenPoolIndex = - (await supernovaPool.token0()) === oeth.address ? 0 : 1; - const assetReserves = oTokenPoolIndex === 0 ? _reserve1 : _reserve0; - const oTokenReserves = oTokenPoolIndex === 0 ? _reserve0 : _reserve1; - - const diff = parseInt( - assetReserves.sub(oTokenReserves).div(oethUnits("1")).toString() - ); - - if (diff > 0) { - cfg.poolAddOethAmount += diff; - } else if (diff < 0) { - cfg.poolAddWethAmount += -diff; - } - } - - // Add WETH to the pool directly. - if (cfg.poolAddWethAmount > 0) { - log(`Adding ${cfg.poolAddWethAmount} WETH to the pool`); - const wethAmount = parseUnits(cfg.poolAddWethAmount.toString(), 18); - await weth.connect(josh).transfer(supernovaPool.address, wethAmount); - } - - // Add OETH to the pool directly. - if (cfg.poolAddOethAmount > 0) { - log(`Adding ${cfg.poolAddOethAmount} OETH to the pool`); - const oethAmount = parseUnits(cfg.poolAddOethAmount.toString(), 18); - await weth.connect(josh).approve(oethVault.address, oethAmount); - await oethVault.connect(josh).mint(oethAmount); - await oeth.connect(josh).transfer(supernovaPool.address, oethAmount); - } - - // Force reserves to match balances. - await supernovaPool.sync(); - - return { - ...fixture, - oethVaultSigner, - supernovaRewardToken, - supernovaPool, - supernovaGauge, - supernovaAMOStrategy: cOETHSupernovaAMOStrategy, - }; -} - // Unit test cross chain fixture where both contracts are deployed on the same chain for the // purposes of unit testing async function crossChainFixtureUnit() { @@ -1889,5 +1726,4 @@ module.exports = { rebalancerModuleFixture, crossChainFixtureUnit, crossChainFixture, - supernovaOETHAMOFixture, }; diff --git a/contracts/test/strategies/oeth-supernova-amo.mainnet.fork-test.js b/contracts/test/strategies/oeth-supernova-amo.mainnet.fork-test.js deleted file mode 100644 index cee4c21b40..0000000000 --- a/contracts/test/strategies/oeth-supernova-amo.mainnet.fork-test.js +++ /dev/null @@ -1,134 +0,0 @@ -const { supernovaOETHAMOFixture, createFixtureLoader } = require("../_fixture"); -const { - shouldBehaveLikeAlgebraAmoStrategy, -} = require("../behaviour/algebraAmoStrategy"); - -describe("Mainnet Fork Test: OETH Supernova AMO Strategy", function () { - shouldBehaveLikeAlgebraAmoStrategy(async () => { - const scenarioConfig = { - attackerFrontRun: { - moderateAssetIn: "20", - largeAssetIn: "10000", - largeOTokenIn: "10000", - }, - bootstrapPool: { - smallAssetBootstrapIn: "50", - mediumAssetBootstrapIn: "200", - largeAssetBootstrapIn: "500000", - }, - mintValues: { - extraSmall: "0.1", - extraSmallPlus: "0.2", - small: "1", - medium: "2", - }, - poolImbalance: { - lotMoreOToken: { addOToken: 400 }, - littleMoreOToken: { addOToken: 2 }, - lotMoreAsset: { addAsset: 400 }, - littleMoreAsset: { addAsset: 2 }, - }, - smallPoolShare: { - bootstrapAssetSwapIn: "100", - bigLiquidityAsset: "50", - oTokenBuffer: "100", - stressSwapOToken: "30", - stressSwapAsset: "50", - stressSwapAssetAlt: "30", - }, - rebalanceProbe: { - frontRun: { - depositAmount: "200", - failedDepositAmount: "200", - failedDepositAllAmount: "200", - tiltSeedWithdrawAmount: "60", - assetTiltWithdrawAmount: "40", - oTokenTiltWithdrawAmount: "0.001", - }, - lotMoreOToken: { - failedDepositAmount: "200", - partialWithdrawAmount: "40", - smallSwapAssetsToPool: "0.3", - largeSwapAssetsToPool: "30", - nearMaxSwapAssetsToPool: "44", - excessiveSwapAssetsToPool: "2000", - disallowedSwapOTokensToPool: "0.0001", - }, - littleMoreOToken: { - depositAmount: "12", - partialWithdrawAmount: "10", - smallSwapAssetsToPool: "0.3", - excessiveSwapAssetsToPool: "50", - disallowedSwapOTokensToPool: "0.0001", - }, - lotMoreAsset: { - failedDepositAmount: "60", - partialWithdrawAmount: "10", - smallSwapOTokensToPool: "0.03", - largeSwapOTokensToPool: "50", - overshootSwapOTokensToPool: "350", - disallowedSwapAssetsToPool: "0.00001", - }, - littleMoreAsset: { - depositAmount: "18", - partialWithdrawAmount: "10", - smallSwapOTokensToPool: "0.8", - overshootSwapOTokensToPool: "110", - disallowedSwapAssetsToPool: "0.00001", - }, - }, - insolvent: { - swapOTokensToPool: "0.1", - }, - harvest: { - collectedBy: "strategist", - }, - }; - - return { - scenarioConfig, - loadFixture: async ({ - assetMintAmount = 0, - depositToStrategy = false, - balancePool = false, - poolAddAssetAmount = 0, - poolAddOTokenAmount = 0, - } = {}) => { - const fixtureLoader = await createFixtureLoader( - supernovaOETHAMOFixture, - { - assetMintAmount, - depositToStrategy, - balancePool, - poolAddWethAmount: poolAddAssetAmount, - poolAddOethAmount: poolAddOTokenAmount, - } - ); - - const fixture = await fixtureLoader(); - const oTokenPoolIndex = - (await fixture.supernovaPool.token0()) === fixture.oeth.address - ? 0 - : 1; - - return { - assetToken: fixture.weth, - oToken: fixture.oeth, - rewardToken: fixture.supernovaRewardToken, - amoStrategy: fixture.supernovaAMOStrategy, - pool: fixture.supernovaPool, - gauge: fixture.supernovaGauge, - governor: fixture.timelock, - timelock: fixture.timelock, - strategist: fixture.strategist, - nick: fixture.josh, - oTokenPoolIndex, - vaultSigner: fixture.oethVaultSigner, - vault: fixture.oethVault, - harvester: fixture.oethHarvester, - scenarioConfig, - }; - }, - }; - }); -});