diff --git a/contracts/contracts/mocks/MockNonRebasing.sol b/contracts/contracts/mocks/MockNonRebasing.sol index 61bbe79c6e..b3ad870347 100644 --- a/contracts/contracts/mocks/MockNonRebasing.sol +++ b/contracts/contracts/mocks/MockNonRebasing.sol @@ -47,7 +47,7 @@ contract MockNonRebasing { } function redeemOusd(address _vaultContract, uint256 _amount) public { - IVault(_vaultContract).redeem(_amount, 0); + IVault(_vaultContract).requestWithdrawal(_amount); } function approveFor( diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index d8cfe3777d..53970e6b09 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -623,46 +623,6 @@ abstract contract VaultCore is VaultInitializer { return balance + queue.claimed - queue.queued; } - /** - * @notice Deprecated. Use calculateRedeemOutput instead. - */ - function calculateRedeemOutputs(uint256 _amount) - external - view - returns (uint256[] memory outputs) - { - outputs = new uint256[](1); - outputs[0] = _calculateRedeemOutput(_amount); - } - - /** - * @notice Calculate the amount of asset received on redeeming OToken. - * @param _amount Amount of OToken to redeem - * @return Amount of asset received - */ - function calculateRedeemOutput(uint256 _amount) - external - view - returns (uint256) - { - return _calculateRedeemOutput(_amount); - } - - /** - * @dev Calculate the amount of asset received on redeeming OToken. - * @param _amount Amount of OToken to redeem - * @return Amount of asset received - */ - function _calculateRedeemOutput(uint256 _amount) - internal - view - virtual - returns (uint256) - { - // Redeem 1:1 with asynchronous withdrawals - return _amount.scaleBy(assetDecimals, 18); - } - /** * @notice Adds WETH to the withdrawal queue if there is a funding shortfall. * @dev is called from the Native Staking strategy when validator withdrawals are processed. diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index fc0731f17b..76878e69d6 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -300,6 +300,11 @@ const configureVault = async () => { await withConfirmation( cVault.connect(sGovernor).setStrategistAddr(strategistAddr) ); + + // Set withdrawal claim delay to 10m + await withConfirmation( + cVault.connect(sGovernor).setWithdrawalClaimDelay(10 * 60) + ); }; /** @@ -331,9 +336,6 @@ const configureOETHVault = async () => { cVault.connect(sGovernor).setStrategistAddr(strategistAddr) ); - // Redeem fee to 0 - await withConfirmation(cVault.connect(sGovernor).setRedeemFeeBps(0)); - // Allocate threshold await withConfirmation( cVault diff --git a/contracts/node.sh b/contracts/node.sh index 52166b041a..84b8fc293c 100755 --- a/contracts/node.sh +++ b/contracts/node.sh @@ -91,8 +91,6 @@ main() done printf "\n" echo "🟢 Node initialized" - - FORK_NETWORK_NAME=$FORK_NETWORK_NAME FORK=true npx hardhat fund --amount 100000 --network localhost --accountsfromenv true & # wait for subprocesses to finish for job in `jobs -p` diff --git a/contracts/package.json b/contracts/package.json index 99dff7e25c..ffcbf28364 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -31,8 +31,8 @@ "lint:js": "eslint \"test/**/*.js\" \"tasks/**/*.js\" \"deploy/**/*.js\"", "lint:sol": "solhint \"contracts/**/*.sol\"", "prettier": "yarn run prettier:js && yarn run prettier:sol", - "prettier:check": "prettier -c \"*.js\" \"deploy/**/*.js\" \"scripts/**/*.js\" \"smoke/**/*.js\" \"scripts/**/*.js\" \"tasks/**/*.js\" \"test/**/*.js\" \"utils/**/*.js\"", - "prettier:js": "prettier --write \"*.js\" \"deploy/**/*.js\" \"scripts/**/*.js\" \"smoke/**/*.js\" \"scripts/**/*.js\" \"tasks/**/*.js\" \"test/**/*.js\" \"utils/**/*.js\"", + "prettier:check": "prettier -c \"*.js\" \"deploy/**/*.js\" \"scripts/**/*.js\" \"scripts/**/*.js\" \"tasks/**/*.js\" \"test/**/*.js\" \"utils/**/*.js\"", + "prettier:js": "prettier --write \"*.js\" \"deploy/**/*.js\" \"scripts/**/*.js\" \"scripts/**/*.js\" \"tasks/**/*.js\" \"test/**/*.js\" \"utils/**/*.js\"", "prettier:sol": "prettier --write --plugin=prettier-plugin-solidity \"contracts/**/*.sol\"", "test": "rm -rf deployments/hardhat && IS_TEST=true npx hardhat test", "test:base": "rm -rf deployments/hardhat && UNIT_TESTS_NETWORK=base IS_TEST=true npx hardhat test", diff --git a/contracts/smoke/mintRedeemTest.js b/contracts/smoke/mintRedeemTest.js deleted file mode 100644 index 65d3683080..0000000000 --- a/contracts/smoke/mintRedeemTest.js +++ /dev/null @@ -1,206 +0,0 @@ -const { fund, mint } = require("../tasks/account"); -const { - usdtUnits, - ousdUnits, - usdcUnits, - daiUnits, - ousdUnitsFormat, - isWithinTolerance, -} = require("../test/helpers"); -const addresses = require("../utils/addresses"); -const erc20Abi = require("../test/abi/erc20.json"); - -let utils, BigNumber, usdt, dai, usdc, ousd, vault, signer, signer2; - -async function fundAccount4(hre) { - await fund( - { - num: 1, - amount: "3000", - }, - hre - ); -} - -const getUsdtBalance = async () => { - return await usdt.connect(signer).balanceOf(signer.address); -}; - -const getDaiBalance = async () => { - return await dai.connect(signer).balanceOf(signer.address); -}; - -const getUsdcBalance = async () => { - return await usdc.connect(signer).balanceOf(signer.address); -}; - -const getOusdBalance = async (signer) => { - return await ousd.connect(signer).balanceOf(signer.address); -}; - -const assertExpectedOusd = (bigNumber, bigNumberExpected, tolerance = 0.03) => { - if (!isWithinTolerance(bigNumber, bigNumberExpected, 0.03)) { - throw new Error( - `Unexpected OUSD value. Expected ${ousdUnitsFormat( - bigNumberExpected - )} with the tolerance of ${tolerance}. Received: ${ousdUnitsFormat( - bigNumber - )}` - ); - } -}; - -const assertExpectedStablecoins = ( - usdtBn, - daiBn, - usdcBn, - unitsExpected, - tolerance = 0.03 -) => { - // adjust decimals of all stablecoins to 18 so they are easier to compare - const adjustedUsdt = usdtBn.mul(BigNumber.from("1000000000000")); - const adjustedUsdc = usdcBn.mul(BigNumber.from("1000000000000")); - const allStablecoins = adjustedUsdt.add(adjustedUsdc).add(daiBn); - const stableCoinsExpected = utils.parseUnits(unitsExpected, 18); - - if (!isWithinTolerance(allStablecoins, stableCoinsExpected, 0.03)) { - throw new Error( - `Unexpected value. Expected to receive total stablecoin units ${ousdUnitsFormat( - stableCoinsExpected - )} with the tolerance of ${tolerance}. Received: ${ousdUnitsFormat( - allStablecoins - )}` - ); - } -}; - -async function setup(hre) { - utils = hre.ethers.utils; - BigNumber = hre.ethers.BigNumber; - ousd = await hre.ethers.getContractAt("OUSD", addresses.mainnet.OUSDProxy); - usdt = await hre.ethers.getContractAt(erc20Abi, addresses.mainnet.USDT); - dai = await hre.ethers.getContractAt(erc20Abi, addresses.mainnet.DAI); - usdc = await hre.ethers.getContractAt(erc20Abi, addresses.mainnet.USDC); - vault = await ethers.getContractAt("IVault", addresses.mainnet.VaultProxy); - signer = (await hre.ethers.getSigners())[4]; - signer2 = (await hre.ethers.getSigners())[5]; - - await fundAccount4(hre); -} - -async function beforeDeploy(hre) { - // fund stablecoins to the 4th account in signers - await setup(hre); - - const usdtBeforeMint = await getUsdtBalance(); - const ousdBeforeMint = await getOusdBalance(signer); - const usdtToMint = "1100"; - await mint( - { - num: 1, - amount: usdtToMint, - }, - hre - ); - - const usdtAfterMint = await getUsdtBalance(); - const ousdAfterMint = await getOusdBalance(signer); - - const expectedUsdt = usdtBeforeMint.sub(usdtUnits(usdtToMint)); - if (!usdtAfterMint.eq(expectedUsdt)) { - throw new Error( - `Incorrect usdt value. Got ${usdtAfterMint.toString()} expected: ${expectedUsdt.toString()}` - ); - } - - const expectedOusd = ousdBeforeMint.add(ousdUnits(usdtToMint)); - assertExpectedOusd(ousdAfterMint, expectedOusd); - - return { - ousdBeforeMint, - ousdAfterMint, - }; -} - -const testMint = async (hre, beforeDeployData) => { - const ousdBeforeMint = await getOusdBalance(signer); - await mint( - { - num: 1, - amount: "500", - }, - hre - ); - - const ousdAfterMint = await getOusdBalance(signer); - - if (!beforeDeployData.ousdAfterMint.eq(ousdBeforeMint)) { - throw new Error( - `Deploy changed the amount of ousd in user's account from ${ousdUnitsFormat( - beforeDeployData.ousdAfterMint - )} to ${ousdUnitsFormat(ousdBeforeMint)}` - ); - } - - return ousdAfterMint; -}; - -const testRedeem = async (ousdAfterMint) => { - const usdtBeforeRedeem = await getUsdtBalance(); - const daiBeforeRedeem = await getDaiBalance(); - const usdcBeforeRedeem = await getUsdcBalance(); - - const unitsToRedeem = "800"; - const ousdToRedeem = ousdUnits(unitsToRedeem); - await vault.connect(signer).redeem(ousdToRedeem, ousdUnits("770")); - - const ousdAfterRedeem = await getOusdBalance(signer); - const usdtAfterRedeem = await getUsdtBalance(); - const daiAfterRedeem = await getDaiBalance(); - const usdcAfterRedeem = await getUsdcBalance(); - - const expectedOusd = ousdAfterMint.sub(ousdToRedeem); - assertExpectedOusd(ousdAfterRedeem, expectedOusd, 0.0); - - assertExpectedStablecoins( - usdtAfterRedeem.sub(usdtBeforeRedeem), - daiAfterRedeem.sub(daiBeforeRedeem), - usdcAfterRedeem.sub(usdcBeforeRedeem), - "800" - ); -}; - -const testTransfer = async () => { - const ousdSenderBeforeSend = await getOusdBalance(signer); - const ousdReceiverBeforeSend = await getOusdBalance(signer2); - const ousdToTransfer = "245.5"; - - await ousd - .connect(signer) - .transfer(signer2.address, ousdUnits(ousdToTransfer)); - - const ousdSenderAfterSend = await getOusdBalance(signer); - const ousdReceiverAfterSend = await getOusdBalance(signer2); - - assertExpectedOusd( - ousdSenderAfterSend, - ousdSenderBeforeSend.sub(ousdUnits(ousdToTransfer)), - 0.0 - ); - assertExpectedOusd( - ousdReceiverAfterSend, - ousdReceiverBeforeSend.add(ousdUnits(ousdToTransfer)), - 0.0 - ); -}; - -async function afterDeploy(hre, beforeDeployData) { - const ousdAfterMint = await testMint(hre, beforeDeployData); - await testRedeem(ousdAfterMint); - await testTransfer(); -} - -module.exports = { - beforeDeploy, - afterDeploy, -}; diff --git a/contracts/tasks/account.js b/contracts/tasks/account.js index 5d211cbb2e..9f146cc7db 100644 --- a/contracts/tasks/account.js +++ b/contracts/tasks/account.js @@ -1,19 +1,3 @@ -// USDT has its own ABI because of non standard returns -const usdtAbi = require("../test/abi/usdt.json").abi; -const usdsAbi = require("../test/abi/erc20.json"); -const tusdAbi = require("../test/abi/erc20.json"); -const usdcAbi = require("../test/abi/erc20.json"); -const { hardhatSetBalance, setERC20TokenBalance } = require("../test/_fund"); - -// By default we use 10 test accounts. -const defaultNumAccounts = 10; - -// The first 4 hardhat accounts are reserved for use as the deployer, governor, etc... -const defaultAccountIndex = 4; - -// By default, fund each test account with 10k worth of each stable coin. -const defaultFundAmount = 10000; - /** * Prints test accounts. */ @@ -40,160 +24,6 @@ async function accounts(taskArguments, hre, privateKeys) { } } -/** - * Funds test accounts on local or fork with USDS, USDT, USDC and TUSD. - */ -async function fund(taskArguments, hre) { - const addresses = require("../utils/addresses"); - const { isFork, isLocalhost } = require("../test/helpers"); - - if (!isFork && !isLocalhost) { - throw new Error("Task can only be used on local or fork"); - } - - if (hre.network.config.chainId !== 1) { - // Skip funding if it's not mainnet - return; - } - - if (!process.env.ACCOUNTS_TO_FUND) { - // No need to fund accounts if no accounts to fund - return; - } - - let usdt, usds, tusd, usdc; - if (isFork) { - usdt = await hre.ethers.getContractAt(usdtAbi, addresses.mainnet.USDT); - usds = await hre.ethers.getContractAt(usdsAbi, addresses.mainnet.USDS); - tusd = await hre.ethers.getContractAt(tusdAbi, addresses.mainnet.TUSD); - usdc = await hre.ethers.getContractAt(usdcAbi, addresses.mainnet.USDC); - } else { - usdt = await hre.ethers.getContract("MockUSDT"); - usds = await hre.ethers.getContract("MockUSDS"); - tusd = await hre.ethers.getContract("MockTUSD"); - usdc = await hre.ethers.getContract("MockUSDC"); - } - - const signers = await hre.ethers.getSigners(); - - let accountsToFund; - let signersToFund; - - if (taskArguments.accountsfromenv) { - if (!isFork) { - throw new Error("accountsfromenv param only works in fork mode"); - } - accountsToFund = process.env.ACCOUNTS_TO_FUND.split(","); - } else { - const numAccounts = Number(taskArguments.num) || defaultNumAccounts; - const accountIndex = Number(taskArguments.account) || defaultAccountIndex; - - signersToFund = signers.splice(accountIndex, numAccounts); - accountsToFund = signersToFund.map((signer) => signer.address); - } - - const fundAmount = taskArguments.amount || defaultFundAmount; - - console.log(`USDS: ${usds.address}`); - console.log(`USDC: ${usdc.address}`); - console.log(`USDT: ${usdt.address}`); - console.log(`TUSD: ${tusd.address}`); - - const contractDataList = [ - { - name: "eth", - token: null, - }, - { - name: "usds", - token: usds, - }, - { - name: "usdc", - token: usdc, - }, - { - name: "usdt", - token: usdt, - }, - ]; - - for (let i = 0; i < accountsToFund.length; i++) { - const currentAccount = accountsToFund[i]; - await Promise.all( - contractDataList.map(async (contractData) => { - const { token, name } = contractData; - const usedFundAmount = token !== null ? fundAmount : "1000000"; - - if (!token) { - await hardhatSetBalance(currentAccount, usedFundAmount); - } else { - await setERC20TokenBalance( - currentAccount, - token, - usedFundAmount, - hre - ); - } - - console.log( - `Funded ${currentAccount} with ${usedFundAmount} ${name.toUpperCase()}` - ); - }) - ); - } -} - -// Sends OUSD to a destination address. -async function transfer(taskArguments) { - const { - ousdUnits, - ousdUnitsFormat, - isFork, - isLocalHost, - } = require("../test/helpers"); - - if (!isFork && !isLocalHost) { - throw new Error("Task can only be used on local or fork"); - } - - const ousdProxy = await ethers.getContract("OUSDProxy"); - const ousd = await ethers.getContractAt("OUSD", ousdProxy.address); - - const index = Number(taskArguments.index); - const amount = taskArguments.amount; - const to = taskArguments.to; - - const signers = await hre.ethers.getSigners(); - const signer = signers[index]; - - // Print balances prior to the transfer - console.log("\nOUSD balances prior transfer"); - console.log( - `${signer.address}: ${ousdUnitsFormat( - await ousd.balanceOf(signer.address) - )} OUSD` - ); - console.log(`${to}: ${ousdUnitsFormat(await ousd.balanceOf(to))} OUSD`); - - // Send OUSD. - console.log( - `\nTransferring ${amount} OUSD from ${signer.address} to ${to}...` - ); - await ousd.connect(signer).transfer(to, ousdUnits(amount)); - - // Print balances after to the transfer - console.log("\nOUSD balances after transfer"); - console.log( - `${signer.address}: ${ousdUnitsFormat( - await ousd.balanceOf(signer.address) - )} OUSD` - ); - console.log(`${to}: ${ousdUnitsFormat(await ousd.balanceOf(to))} OUSD`); -} - module.exports = { accounts, - fund, - transfer, }; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 32c5606409..c2065c31fc 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -1,5 +1,4 @@ const { subtask, task, types } = require("hardhat/config"); -const { fund } = require("./account"); const { debug } = require("./debug"); const { env } = require("./env"); const { setActionVars, updateAction } = require("./defender"); @@ -50,14 +49,12 @@ const { depositToStrategy, mint, rebase, - redeem, requestWithdrawal, claimWithdrawal, snapVault, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, - yieldTask, } = require("./vault"); const { checkDelta, getDelta, takeSnapshot } = require("./valueChecker"); const { @@ -148,17 +145,6 @@ const log = require("../utils/logger")("tasks"); // Environment tasks. task("env", "Check env vars are properly set for a Mainnet deployment", env); -// Account tasks. -task("fund", "Fund accounts on local or fork") - .addOptionalParam("num", "Number of accounts to fund") - .addOptionalParam("index", "Account start index") - .addOptionalParam("amount", "Stable coin amount to fund each account with") - .addOptionalParam( - "accountsfromenv", - "Fund accounts from the .env file instead of mnemonic" - ) - .setAction(fund); - // Debug tasks. task("debug", "Print info about contracts and their configs", debug); @@ -166,7 +152,7 @@ task("debug", "Print info about contracts and their configs", debug); subtask("allowance", "Get the token allowance an owner has given to a spender") .addParam( "symbol", - "Symbol of the token. eg OETH, WETH, USDT or OGV", + "Symbol of the token. eg OETH, WETH, USDC or OGV", undefined, types.string ) @@ -192,7 +178,7 @@ task("allowance").setAction(async (_, __, runSuper) => { subtask("balance", "Get the token balance of an account or contract") .addParam( "symbol", - "Symbol of the token. eg OETH, WETH, USDT or OGV", + "Symbol of the token. eg OETH, WETH, USDC or OGV", undefined, types.string ) @@ -214,7 +200,7 @@ task("balance").setAction(async (_, __, runSuper) => { subtask("approve", "Approve an account or contract to spend tokens") .addParam( "symbol", - "Symbol of the token. eg OETH, WETH, USDT or OGV", + "Symbol of the token. eg OETH, WETH, USDC or OGV", undefined, types.string ) @@ -238,7 +224,7 @@ task("approve").setAction(async (_, __, runSuper) => { subtask("transfer", "Transfer tokens to an account or contract") .addParam( "symbol", - "Symbol of the token. eg OETH, WETH, USDT or OGV", + "Symbol of the token. eg OETH, WETH, USDC or OGV", undefined, types.string ) @@ -252,7 +238,7 @@ task("transfer").setAction(async (_, __, runSuper) => { subtask("transferFrom", "Transfer tokens from an account or contract") .addParam( "symbol", - "Symbol of the token. eg OETH, WETH, USDT or OGV", + "Symbol of the token. eg OETH, WETH, USDC or OGV", undefined, types.string ) @@ -353,12 +339,10 @@ task("rebase").setAction(async (_, __, runSuper) => { return runSuper(); }); -task("yield", "Artificially generate yield on the OUSD Vault", yieldTask); - subtask("mint", "Mint OTokens from the Vault using collateral assets") .addOptionalParam( "asset", - "Symbol of the collateral asset to deposit. eg WETH, wS, USDT, DAI or USDC", + "Symbol of the collateral asset to deposit. eg WETH, wS or USDC", undefined, types.string ) @@ -386,25 +370,6 @@ task("mint").setAction(async (_, __, runSuper) => { return runSuper(); }); -subtask("redeem", "Redeem OTokens for collateral assets from the Vault") - .addParam("amount", "Amount of OTokens to burn", undefined, types.float) - .addOptionalParam( - "symbol", - "Symbol of the OToken. eg OETH or OUSD", - "OETH", - types.string - ) - .addOptionalParam( - "min", - "Minimum amount of collateral to receive", - 0, - types.float - ) - .setAction(redeem); -task("redeem").setAction(async (_, __, runSuper) => { - return runSuper(); -}); - subtask( "depositToStrategy", "Deposits vault collateral assets to a vault strategy" diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index a8a3d6be4c..540cb0bd09 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -1,7 +1,6 @@ const { formatUnits, parseUnits } = require("ethers/lib/utils"); const { getBlock } = require("./block"); -const addresses = require("../utils/addresses"); const { resolveAsset } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); const { logTxDetails } = require("../utils/txLogger"); @@ -198,57 +197,6 @@ async function rebase({ symbol }, hre) { await logTxDetails(tx, "rebase"); } -/** - * Artificially generate yield on the vault by sending it USDT. - */ -async function yieldTask(_, hre) { - const usdtAbi = require("../test/abi/usdt.json").abi; - const { - ousdUnitsFormat, - usdtUnits, - usdtUnitsFormat, - isFork, - isLocalhost, - } = require("../test/helpers"); - if (!isFork && !isLocalhost) { - throw new Error("Task can only be used on local or fork"); - } - - let richSigner, usdt; - if (isFork) { - await hre.network.provider.request({ - method: "hardhat_impersonateAccount", - params: [addresses.mainnet.Binance], - }); - richSigner = await hre.ethers.provider.getSigner(addresses.mainnet.Binance); - usdt = await hre.ethers.getContractAt(usdtAbi, addresses.mainnet.USDT); - } else { - const signers = await hre.ethers.getSigners(); - richSigner = signers; - usdt = await hre.ethers.getContract("MockUSDT"); - } - - const { vault, oToken } = await getContracts(hre, "OUSD"); - - log("Sending yield to vault"); - let usdtBalance = await usdt.balanceOf(vault.address); - log("USDT vault balance", usdtUnitsFormat(usdtBalance)); - let vaultValue = await vault.totalValue(); - log("Vault value", ousdUnitsFormat(vaultValue)); - let supply = await oToken.totalSupply(); - log("OUSD supply", ousdUnitsFormat(supply)); - - // Transfer 100k USDT to the vault. - await usdt.connect(richSigner).transfer(vault.address, usdtUnits("100000")); - - usdtBalance = await usdt.balanceOf(vault.address); - log("USDT vault balance", usdtUnitsFormat(usdtBalance)); - vaultValue = await vault.totalValue(); - log("Vault value", ousdUnitsFormat(vaultValue)); - supply = await oToken.totalSupply(); - log("OUSD supply", ousdUnitsFormat(supply)); -} - /** * Call the Vault's admin pauseCapital method. */ @@ -312,19 +260,6 @@ async function mint({ amount, asset, symbol, min, approve }, hre) { await logTxDetails(tx, "mint"); } -async function redeem({ amount, min, symbol }, hre) { - const signer = await getSigner(); - - const { vault } = await getContracts(hre, symbol); - - const oTokenUnits = parseUnits(amount.toString()); - const minUnits = parseUnits(min.toString()); - - log(`About to redeem ${amount} ${symbol}`); - const tx = await vault.connect(signer).redeem(oTokenUnits, minUnits); - await logTxDetails(tx, "redeem"); -} - async function resolveStrategyAddress(strategy, hre) { let strategyAddr = strategy; if (!strategy.match(ethereumAddress)) { @@ -476,12 +411,10 @@ module.exports = { depositToStrategy, mint, rebase, - redeem, requestWithdrawal, claimWithdrawal, snapVault, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, - yieldTask, }; diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 71e34c15db..ef5a810b5b 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -216,7 +216,7 @@ const simpleOETHFixture = deployments.createFixture(async () => { }; }); -const getVaultAndTokenConracts = async () => { +const getVaultAndTokenContracts = async () => { const ousdProxy = await ethers.getContract("OUSDProxy"); const vaultProxy = await ethers.getContract("VaultProxy"); @@ -453,9 +453,7 @@ const createAccountTypes = async ({ vault, ousd, ousdUnlocked, deploy }) => { // Allow matt to burn OUSD await vault.connect(governor).setStrategistAddr(matt.address); // matt burn remaining OUSD - await vault - .connect(matt) - .redeem(ousd.balanceOf(matt.address), ousdUnits("0")); + await vault.connect(matt).requestWithdrawal(ousd.balanceOf(matt.address)); return { // StdRebasing account type: @@ -523,7 +521,7 @@ const loadTokenTransferFixture = deployments.createFixture(async () => { const { governorAddr, multichainStrategistAddr, timelockAddr } = await getNamedAccounts(); - const vaultAndTokenConracts = await getVaultAndTokenConracts(); + const vaultAndTokenContracts = await getVaultAndTokenContracts(); const signers = await hre.ethers.getSigners(); let governor = signers[1]; @@ -531,15 +529,15 @@ const loadTokenTransferFixture = deployments.createFixture(async () => { log("Creating account types..."); const accountTypes = await createAccountTypes({ - ousd: vaultAndTokenConracts.ousd, - ousdUnlocked: vaultAndTokenConracts.ousdUnlocked, - vault: vaultAndTokenConracts.vault, + ousd: vaultAndTokenContracts.ousd, + ousdUnlocked: vaultAndTokenContracts.ousdUnlocked, + vault: vaultAndTokenContracts.vault, deploy: deployments.deploy, }); log("Account types created."); return { - ...vaultAndTokenConracts, + ...vaultAndTokenContracts, ...accountTypes, governorAddr, strategistAddr: multichainStrategistAddr, @@ -569,7 +567,7 @@ const defaultFixture = deployments.createFixture(async () => { const { governorAddr, multichainStrategistAddr, timelockAddr } = await getNamedAccounts(); - const vaultAndTokenConracts = await getVaultAndTokenConracts(); + const vaultAndTokenConracts = await getVaultAndTokenContracts(); const harvesterProxy = await ethers.getContract("HarvesterProxy"); const harvester = await ethers.getContractAt( diff --git a/contracts/test/governance/oethb-timelock.base.fork-test.js b/contracts/test/governance/oethb-timelock.base.fork-test.js index 279e23db98..d54e410a34 100644 --- a/contracts/test/governance/oethb-timelock.base.fork-test.js +++ b/contracts/test/governance/oethb-timelock.base.fork-test.js @@ -1,8 +1,8 @@ const { createFixtureLoader } = require("../_fixture"); const { defaultBaseFixture } = require("../_fixture-base"); const { expect } = require("chai"); -const addresses = require("../../utils/addresses"); const { advanceTime, advanceBlocks } = require("../helpers"); +const { parseUnits } = require("ethers/lib/utils"); const baseFixture = createFixtureLoader(defaultBaseFixture); @@ -15,9 +15,10 @@ describe("ForkTest: OETHb Timelock", function () { it("Multisig can propose and execute on Timelock", async () => { const { guardian, timelock, oethbVault } = fixture; + const newBufferValue = parseUnits("0.1", 18); const calldata = oethbVault.interface.encodeFunctionData( - "setDripper(address)", - [addresses.dead] + "setVaultBuffer(uint256)", + [newBufferValue] ); const args = [ @@ -41,6 +42,6 @@ describe("ForkTest: OETHb Timelock", function () { await timelock.connect(guardian).executeBatch(...args); - expect(await oethbVault.dripper()).to.eq(addresses.dead); + expect(await oethbVault.vaultBuffer()).to.eq(newBufferValue); }); }); diff --git a/contracts/test/strategies/base/aerodrome-amo.base.fork-test.js b/contracts/test/strategies/base/aerodrome-amo.base.fork-test.js index 7ecc6fab08..a78a97bcde 100644 --- a/contracts/test/strategies/base/aerodrome-amo.base.fork-test.js +++ b/contracts/test/strategies/base/aerodrome-amo.base.fork-test.js @@ -1406,7 +1406,7 @@ describe("ForkTest: Aerodrome AMO Strategy (Base)", async function () { const user = userOverride || rafael; amount = amount || oethUnits("5"); - const balance = weth.balanceOf(user.address); + const balance = await weth.balanceOf(user.address); if (balance < amount) { await setERC20TokenBalance(user.address, weth, amount + balance, hre); } @@ -1433,7 +1433,7 @@ describe("ForkTest: Aerodrome AMO Strategy (Base)", async function () { await oethbVault.connect(nick).mint(weth.address, _amount, _amount); } - const balance = weth.balanceOf(user.address); + const balance = await weth.balanceOf(user.address); if (balance < amount) { await setERC20TokenBalance(user.address, weth, amount + balance, hre); } diff --git a/contracts/test/strategies/base/curve-amo.base.fork-test.js b/contracts/test/strategies/base/curve-amo.base.fork-test.js index 8b7d0f56c1..4dd130bdce 100644 --- a/contracts/test/strategies/base/curve-amo.base.fork-test.js +++ b/contracts/test/strategies/base/curve-amo.base.fork-test.js @@ -162,8 +162,13 @@ describe("Base Fork Test: Curve AMO strategy", function () { ); const balance = await weth.balanceOf(user.address); - if (balance < amount) { - await setERC20TokenBalance(user.address, weth, amount + balance, hre); + if (balance.lt(amount)) { + await setERC20TokenBalance( + user.address, + weth, + amount.add(balance), + hre + ); } await weth.connect(user).transfer(curveAMOStrategy.address, amount); @@ -395,7 +400,7 @@ describe("Base Fork Test: Curve AMO strategy", function () { }); it("Should deposit when pool is heavily unbalanced with OETH", async () => { - await unbalancePool({ oethbAmount: defaultDeposit.mul(20) }); + await unbalancePool({ oethbAmount: defaultDeposit.mul(3) }); const checkBalanceBefore = await curveAMOStrategy.checkBalance( weth.address @@ -427,7 +432,8 @@ describe("Base Fork Test: Curve AMO strategy", function () { }); it("Should deposit when pool is heavily unbalanced with WETH", async () => { - await unbalancePool({ wethbAmount: defaultDeposit.mul(20) }); + // No need to make it further unbalanced as WETH is already high + // await unbalancePool({ wethbAmount: defaultDeposit.mul(2) }); const checkBalanceBefore = await curveAMOStrategy.checkBalance( weth.address @@ -767,8 +773,8 @@ describe("Base Fork Test: Curve AMO strategy", function () { amount = amount || defaultDeposit; const balance = await weth.balanceOf(user.address); - if (balance < amount) { - await setERC20TokenBalance(user.address, weth, amount + balance, hre); + if (balance.lt(amount)) { + await setERC20TokenBalance(user.address, weth, amount.add(balance), hre); } await weth.connect(user).approve(oethbVault.address, amount); await oethbVault.connect(user).mint(weth.address, amount, amount); @@ -793,9 +799,14 @@ describe("Base Fork Test: Curve AMO strategy", function () { if (balanceWETH.gt(balanceOETH)) { const amount = balanceWETH.sub(balanceOETH); - const balance = weth.balanceOf(nick.address); - if (balance < amount) { - await setERC20TokenBalance(nick.address, weth, amount + balance, hre); + const balance = await weth.balanceOf(nick.address); + if (balance.lt(amount)) { + await setERC20TokenBalance( + nick.address, + weth, + amount.add(balance), + hre + ); } await weth .connect(nick) @@ -809,9 +820,14 @@ describe("Base Fork Test: Curve AMO strategy", function () { .connect(nick)["add_liquidity(uint256[],uint256)"]([0, amount], 0); } else if (balanceWETH.lt(balanceOETH)) { const amount = balanceOETH.sub(balanceWETH); - const balance = weth.balanceOf(nick.address); - if (balance < amount) { - await setERC20TokenBalance(nick.address, weth, amount + balance, hre); + const balance = await weth.balanceOf(nick.address); + if (balance.lt(amount)) { + await setERC20TokenBalance( + nick.address, + weth, + amount.add(balance), + hre + ); } await weth.connect(nick).approve(curvePool.address, amount); // prettier-ignore @@ -836,12 +852,12 @@ describe("Base Fork Test: Curve AMO strategy", function () { } if (wethbAmount) { - const balance = weth.balanceOf(nick.address); - if (balance < wethbAmount) { + const balance = await weth.balanceOf(nick.address); + if (balance.lt(wethbAmount)) { await setERC20TokenBalance( nick.address, weth, - wethbAmount + balance, + wethbAmount.add(balance), hre ); } @@ -855,12 +871,12 @@ describe("Base Fork Test: Curve AMO strategy", function () { await curvePool .connect(nick)["add_liquidity(uint256[],uint256)"]([wethbAmount, 0], 0); } else { - const balance = weth.balanceOf(nick.address); - if (balance < oethbAmount) { + const balance = await weth.balanceOf(nick.address); + if (balance.lt(oethbAmount)) { await setERC20TokenBalance( nick.address, weth, - oethbAmount + balance, + oethbAmount.add(balance), hre ); } diff --git a/contracts/test/strategies/convex.js b/contracts/test/strategies/convex.js index 599d0556e7..9f1da88d7d 100644 --- a/contracts/test/strategies/convex.js +++ b/contracts/test/strategies/convex.js @@ -63,7 +63,7 @@ describe("Convex Strategy", function () { await expectApproxSupply(ousd, ousdUnits("200")); await mint("10000.00", usdc); await vault.connect(governor).set; - await vault.connect(strategist).redeem(ousdUnits("10000"), 0); + await vault.connect(strategist).requestWithdrawal(ousdUnits("10000")); await expectApproxSupply(ousd, ousdUnits("200")); }); }); diff --git a/contracts/test/strategies/curve-amo-oeth.mainnet.fork-test.js b/contracts/test/strategies/curve-amo-oeth.mainnet.fork-test.js index 7992904afc..4accfb546a 100644 --- a/contracts/test/strategies/curve-amo-oeth.mainnet.fork-test.js +++ b/contracts/test/strategies/curve-amo-oeth.mainnet.fork-test.js @@ -167,8 +167,13 @@ describe("Curve AMO OETH strategy", function () { ); const balance = await weth.balanceOf(user.address); - if (balance < amount) { - await setERC20TokenBalance(user.address, weth, amount + balance, hre); + if (balance.lt(amount)) { + await setERC20TokenBalance( + user.address, + weth, + amount.add(balance), + hre + ); } await weth.connect(user).transfer(curveAMOStrategy.address, amount); @@ -971,8 +976,8 @@ describe("Curve AMO OETH strategy", function () { amount = amount || defaultDeposit; const balance = await weth.balanceOf(user.address); - if (balance < amount) { - await setERC20TokenBalance(user.address, weth, amount + balance, hre); + if (balance.lt(amount)) { + await setERC20TokenBalance(user.address, weth, amount.add(balance), hre); } await weth.connect(user).approve(oethVault.address, 0); @@ -999,9 +1004,14 @@ describe("Curve AMO OETH strategy", function () { if (balanceHardAsset.sub(balanceOToken) > 0) { const amount = balanceHardAsset.sub(balanceOToken); - const balance = weth.balanceOf(nick.address); - if (balance < amount) { - await setERC20TokenBalance(nick.address, weth, amount + balance, hre); + const balance = await weth.balanceOf(nick.address); + if (balance.lt(amount)) { + await setERC20TokenBalance( + nick.address, + weth, + amount.add(balance), + hre + ); } await weth .connect(nick) @@ -1013,11 +1023,16 @@ describe("Curve AMO OETH strategy", function () { // prettier-ignore await curvePool .connect(nick)["add_liquidity(uint256[],uint256)"]([amount, 0], 0); - } else if (balanceHardAsset.sub(balanceOToken) < 0) { + } else if (balanceHardAsset.sub(balanceOToken).lt(0)) { const amount = balanceOToken.sub(balanceHardAsset); - const balance = weth.balanceOf(nick.address); - if (balance < amount) { - await setERC20TokenBalance(nick.address, weth, amount + balance, hre); + const balance = await weth.balanceOf(nick.address); + if (balance.lt(amount)) { + await setERC20TokenBalance( + nick.address, + weth, + amount.add(balance), + hre + ); } await weth.connect(nick).approve(curvePool.address, 0); await weth.connect(nick).approve(curvePool.address, amount); @@ -1041,11 +1056,11 @@ describe("Curve AMO OETH strategy", function () { if (wethAmount) { const balance = await weth.balanceOf(nick.address); - if (balance < wethAmount) { + if (balance.lt(wethAmount)) { await setERC20TokenBalance( nick.address, weth, - wethAmount + balance, + wethAmount.add(balance), hre ); } @@ -1056,7 +1071,7 @@ describe("Curve AMO OETH strategy", function () { .connect(nick)["add_liquidity(uint256[],uint256)"]([0, wethAmount], 0); } else { const balance = await weth.balanceOf(nick.address); - if (balance < ousdAmount) { + if (balance.lt(ousdAmount)) { await setERC20TokenBalance( nick.address, weth, diff --git a/contracts/test/strategies/curve-amo-ousd.mainnet.fork-test.js b/contracts/test/strategies/curve-amo-ousd.mainnet.fork-test.js index e8294b615e..f713fb8453 100644 --- a/contracts/test/strategies/curve-amo-ousd.mainnet.fork-test.js +++ b/contracts/test/strategies/curve-amo-ousd.mainnet.fork-test.js @@ -163,8 +163,13 @@ describe("Curve AMO OUSD strategy", function () { ); const balance = await usdc.balanceOf(user.address); - if (balance < amount) { - await setERC20TokenBalance(user.address, usdc, amount + balance, hre); + if (balance.lt(amount)) { + await setERC20TokenBalance( + user.address, + usdc, + amount.add(balance), + hre + ); } await usdc.connect(user).transfer(curveAMOStrategy.address, amount); @@ -975,8 +980,8 @@ describe("Curve AMO OUSD strategy", function () { amount = amount || defaultDeposit.div(1e12); const balance = await usdc.balanceOf(user.address); - if (balance < amount) { - await setERC20TokenBalance(user.address, usdc, amount + balance, hre); + if (balance.lt(amount)) { + await setERC20TokenBalance(user.address, usdc, amount.add(balance), hre); } await usdc.connect(user).approve(ousdVault.address, 0); @@ -1003,9 +1008,14 @@ describe("Curve AMO OUSD strategy", function () { if (balanceHardAsset.sub(balanceOToken) > 0) { const amount = balanceHardAsset.sub(balanceOToken).div(1e12); - const balance = usdc.balanceOf(nick.address); - if (balance < amount) { - await setERC20TokenBalance(nick.address, usdc, amount + balance, hre); + const balance = await usdc.balanceOf(nick.address); + if (balance.lt(amount)) { + await setERC20TokenBalance( + nick.address, + usdc, + amount.add(balance), + hre + ); } await usdc .connect(nick) @@ -1017,11 +1027,16 @@ describe("Curve AMO OUSD strategy", function () { // prettier-ignore await curvePool .connect(nick)["add_liquidity(uint256[],uint256)"]([amount, 0], 0); - } else if (balanceHardAsset.sub(balanceOToken) < 0) { + } else if (balanceHardAsset.sub(balanceOToken).lt(0)) { const amount = balanceOToken.sub(balanceHardAsset).div(1e12); - const balance = usdc.balanceOf(nick.address); - if (balance < amount) { - await setERC20TokenBalance(nick.address, usdc, amount + balance, hre); + const balance = await usdc.balanceOf(nick.address); + if (balance.lt(amount)) { + await setERC20TokenBalance( + nick.address, + usdc, + amount.add(balance), + hre + ); } await usdc.connect(nick).approve(curvePool.address, 0); await usdc.connect(nick).approve(curvePool.address, amount); @@ -1045,11 +1060,11 @@ describe("Curve AMO OUSD strategy", function () { if (usdcAmount) { const balance = await usdc.balanceOf(nick.address); - if (balance < usdcAmount) { + if (balance.lt(usdcAmount)) { await setERC20TokenBalance( nick.address, usdc, - usdcAmount + balance, + usdcAmount.add(balance), hre ); } @@ -1060,7 +1075,7 @@ describe("Curve AMO OUSD strategy", function () { .connect(nick)["add_liquidity(uint256[],uint256)"]([0, usdcAmount], 0); } else { const balance = await usdc.balanceOf(nick.address); - if (balance < ousdAmount.div(1e12)) { + if (balance.lt(ousdAmount.div(1e12))) { await setERC20TokenBalance( nick.address, usdc, diff --git a/contracts/test/vault/compound.js b/contracts/test/vault/compound.js index 8705e6707e..a632a14ff9 100644 --- a/contracts/test/vault/compound.js +++ b/contracts/test/vault/compound.js @@ -12,6 +12,9 @@ const { isFork, expectApproxSupply, } = require("../helpers"); +const { + increase, +} = require("@nomicfoundation/hardhat-network-helpers/dist/src/helpers/time"); describe("Vault with Compound strategy", function () { if (isFork) { @@ -90,10 +93,9 @@ describe("Vault with Compound strategy", function () { await expect(strategist).has.a.balanceOf("50.00", ousd); await ousd.connect(strategist).approve(vault.address, ousdUnits("40.0")); - await vault - .connect(strategist) - .redeem(ousdUnits("40.0"), usdcUnits("35.0")); - expect(await vault.redeemFeeBps()).to.be.eq(0); + await vault.connect(strategist).requestWithdrawal(ousdUnits("40.0")); + await increase(60 * 10); // Advance 10 minutes + await vault.connect(strategist).claimWithdrawal(0); // Assumes request ID is 0 await expect(strategist).has.an.balanceOf("10", ousd); await expect(strategist).has.an.balanceOf("990.0", usdc); @@ -372,7 +374,9 @@ describe("Vault with Compound strategy", function () { ousd ); await vault.connect(governor).setStrategistAddr(user.address); - await vault.connect(user).redeem(ousdUnits(amount.toString()), 0); + await vault + .connect(user) + .requestWithdrawal(ousdUnits(amount.toString())); await expect(user).has.an.approxBalanceOf(start.toString(), ousd); } } diff --git a/contracts/test/vault/harvester.mainnet.fork-test.js b/contracts/test/vault/harvester.mainnet.fork-test.js index ef6818f804..1b6d0887c5 100644 --- a/contracts/test/vault/harvester.mainnet.fork-test.js +++ b/contracts/test/vault/harvester.mainnet.fork-test.js @@ -3,7 +3,6 @@ const { utils, BigNumber } = require("ethers"); const { createFixtureLoader, harvesterFixture } = require("./../_fixture"); const { isCI, oethUnits } = require("./../helpers"); -const { hotDeployOption } = require("../_hot-deploy"); const addresses = require("../../utils/addresses"); const { setERC20TokenBalance } = require("../_fund"); const { parseUnits } = require("ethers").utils; @@ -19,12 +18,6 @@ describe("ForkTest: Harvester", function () { let fixture; beforeEach(async () => { fixture = await loadFixture(); - await hotDeployOption(fixture, null, { - isOethFixture: true, - }); - await hotDeployOption(fixture, null, { - isOethFixture: false, - }); }); // Skipping this since we switched to simple harvester diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index af64fd6163..9953062cb9 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -174,26 +174,8 @@ describe("OETH Vault", function () { }); }); - describe("Redeem", () => { - it("Should return only WETH in redeem calculations", async () => { - const { oethVault, weth } = fixture; - - const outputs = await oethVault.calculateRedeemOutputs( - oethUnits("1234.43") - ); - - const assets = await oethVault.getAllAssets(); - - expect(assets.length).to.equal(outputs.length); - - for (let i = 0; i < assets.length; i++) { - expect(outputs[i]).to.equal( - assets[i] == weth.address ? oethUnits("1234.43") : "0" - ); - } - }); - - it("Should update total supply correctly without redeem fee", async () => { + describe("async withdrawal", () => { + it("Should update total supply correctly", async () => { const { oethVault, oeth, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); @@ -201,7 +183,9 @@ describe("OETH Vault", function () { const vaultBalanceBefore = await weth.balanceOf(oethVault.address); const supplyBefore = await oeth.totalSupply(); - await oethVault.connect(daniel).redeem(oethUnits("10"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await advanceTime(10 * 60); // 10 minutes + await oethVault.connect(daniel).claimWithdrawal(0); const userBalanceAfter = await weth.balanceOf(daniel.address); const vaultBalanceAfter = await weth.balanceOf(oethVault.address); @@ -213,35 +197,7 @@ describe("OETH Vault", function () { expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); }); - it("Should update total supply correctly with redeem fee", async () => { - const { oethVault, oeth, weth, daniel } = fixture; - await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); - - await oethVault - .connect(await impersonateAndFund(await oethVault.governor())) - .setRedeemFeeBps(100); - - const userBalanceBefore = await weth.balanceOf(daniel.address); - const vaultBalanceBefore = await weth.balanceOf(oethVault.address); - const supplyBefore = await oeth.totalSupply(); - - await oethVault.connect(daniel).redeem(oethUnits("10"), "0"); - - const userBalanceAfter = await weth.balanceOf(daniel.address); - const vaultBalanceAfter = await weth.balanceOf(oethVault.address); - const supplyAfter = await oeth.totalSupply(); - - // Make sure the total supply went down - expect(userBalanceAfter.sub(userBalanceBefore)).to.eq( - oethUnits("10").sub(oethUnits("0.1")) - ); - expect(vaultBalanceBefore.sub(vaultBalanceAfter)).to.eq( - oethUnits("10").sub(oethUnits("0.1")) - ); - expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); - }); - - it("Fail to redeem if not enough liquidity available in the vault", async () => { + it("Fail to claim if not enough liquidity available in the vault", async () => { const { oethVault, weth, domen, governor } = fixture; const mockStrategy = await deployWithConfirmation("MockStrategy"); @@ -258,29 +214,26 @@ describe("OETH Vault", function () { await oethVault.connect(domen).mint(weth.address, oethUnits("1.23"), "0"); // Withdraw something more than what the Vault holds - const tx = oethVault.connect(domen).redeem(oethUnits("12.55"), "0"); + await oethVault.connect(domen).requestWithdrawal(oethUnits("12.55")); + await advanceTime(10 * 60); // 10 minutes - await expect(tx).to.revertedWith("Liquidity error"); + const tx = oethVault.connect(domen).claimWithdrawal(0); + await expect(tx).to.revertedWith("Queue pending liquidity"); }); - it("Should redeem zero amount without revert", async () => { + it("Should request withdrawal of zero amount without revert", async () => { const { oethVault, daniel } = fixture; - await oethVault.connect(daniel).redeem(0, 0); + await oethVault.connect(daniel).requestWithdrawal(0); }); - it("Fail to redeem if not enough liquidity", async () => { - const { oethVault, daniel } = fixture; - const tx = oethVault - .connect(daniel) - .redeem(oethUnits("1023232323232"), "0"); - await expect(tx).to.be.revertedWith("Liquidity error"); - }); - it("Should allow every user to redeem", async () => { + it("Should allow every user to withdraw", async () => { const { oethVault, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); - await oethVault.connect(daniel).redeem(oethUnits("10"), oethUnits("0")); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await advanceTime(10 * 60); // 10 minutes + await oethVault.connect(daniel).claimWithdrawal(0); await expect(await weth.balanceOf(oethVault.address)).to.equal(0); }); diff --git a/contracts/test/vault/oeth-vault.mainnet.fork-test.js b/contracts/test/vault/oeth-vault.mainnet.fork-test.js index 5ea2f11db0..59ca11c723 100644 --- a/contracts/test/vault/oeth-vault.mainnet.fork-test.js +++ b/contracts/test/vault/oeth-vault.mainnet.fork-test.js @@ -115,77 +115,6 @@ describe("ForkTest: OETH Vault", function () { .withArgs(josh.address, amount); }); - it("should have 0.1% redeem fee", async () => { - const { oethVault } = fixture; - - expect(await oethVault.redeemFeeBps()).to.equal(10); - }); - - it("should return only WETH in redeem calculations", async () => { - const { oethVault } = fixture; - - const output = await oethVault.calculateRedeemOutputs(oethUnits("123")); - const index = 0; - - expect(output.length).to.equal(1); - expect(output[index]).to.equal(oethUnits("123").mul("9990").div("10000")); - }); - - it("should allow strategist to redeem without fee", async () => { - const { oethVault, strategist, matt, weth, oeth } = fixture; - await depositDiffInWeth(fixture, matt); - - const sGovernor = await impersonateAndFund(addresses.mainnet.Timelock); - // make sure to not trigger rebase on redeem - await oethVault.connect(sGovernor).setRebaseThreshold(oethUnits("11")); - - await weth.connect(matt).transfer(strategist.address, oethUnits("100")); - - const amount = oethUnits("10"); - - await weth.connect(strategist).approve(oethVault.address, amount); - - // Mint 1:1 - await oethVault.connect(strategist).mint(weth.address, amount, amount); - - const oethBalanceBefore = await oeth.balanceOf(strategist.address); - const wethBalanceBefore = await weth.balanceOf(strategist.address); - - // Redeem 1:1 instantly - await oethVault.connect(strategist).redeem(amount, amount); - - const oethBalanceAfter = await oeth.balanceOf(strategist.address); - const wethBalanceAfter = await weth.balanceOf(strategist.address); - - expect(oethBalanceAfter).to.equal(oethBalanceBefore.sub(amount)); - expect(wethBalanceAfter).to.equal(wethBalanceBefore.add(amount)); - }); - - it("should enforce fee on other users for instant redeem", async () => { - const { oethVault, josh, matt, weth, oeth } = fixture; - await depositDiffInWeth(fixture, matt); - - const amount = oethUnits("10"); - const expectedWETH = amount.mul("9990").div("10000"); - - await weth.connect(josh).approve(oethVault.address, amount); - - // Mint 1:1 - await oethVault.connect(josh).mint(weth.address, amount, amount); - - const oethBalanceBefore = await oeth.balanceOf(josh.address); - const wethBalanceBefore = await weth.balanceOf(josh.address); - - // Redeem 1:1 instantly - await oethVault.connect(josh).redeem(amount, expectedWETH); - - const oethBalanceAfter = await oeth.balanceOf(josh.address); - const wethBalanceAfter = await weth.balanceOf(josh.address); - - expect(oethBalanceAfter).to.equal(oethBalanceBefore.sub(amount)); - expect(wethBalanceAfter).to.equal(wethBalanceBefore.add(expectedWETH)); - }); - it("should partially redeem 10 OETH", async () => { const { domen, oeth, oethVault, weth, matt } = fixture; await depositDiffInWeth(fixture, matt); @@ -216,17 +145,6 @@ describe("ForkTest: OETH Vault", function () { .withNamedArgs({ _addr: oethWhaleAddress }); }); - it.skip("should not do full redeem by OETH whale", async () => { - const { oeth, oethVault } = fixture; - - const oethWhaleBalance = await oeth.balanceOf(oethWhaleAddress); - expect(oethWhaleBalance, "no longer an OETH whale").to.gt( - parseUnits("1000", 18) - ); - - const tx = oethVault.connect(oethWhaleSigner).redeem(oethWhaleBalance, 0); - await expect(tx).to.revertedWith("Liquidity error"); - }); it("should request a withdraw by OETH whale", async () => { const { oeth, oethVault } = fixture; @@ -300,12 +218,14 @@ describe("ForkTest: OETH Vault", function () { await oethVault.connect(timelock).withdrawAllFromStrategies(); - const tx = await oethVault + const { nextWithdrawalIndex: requestId } = + await oethVault.withdrawalQueueMetadata(); + + await oethVault .connect(oethWhaleSigner) - .redeem(oethWhaleBalance, 0); - await expect(tx) - .to.emit(oethVault, "Redeem") - .withNamedArgs({ _addr: oethWhaleAddress }); + .requestWithdrawal(oethWhaleBalance); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await await oethVault.connect(oethWhaleSigner).claimWithdrawal(requestId); }); it("Vault should have the right WETH address", async () => { const { oethVault } = fixture; diff --git a/contracts/test/vault/oethb-vault.base.fork-test.js b/contracts/test/vault/oethb-vault.base.fork-test.js index 32e230db8b..81972e7bf7 100644 --- a/contracts/test/vault/oethb-vault.base.fork-test.js +++ b/contracts/test/vault/oethb-vault.base.fork-test.js @@ -51,89 +51,6 @@ describe("ForkTest: OETHb Vault", function () { 0.1 ); }); - - it("Should allow only Strategist to redeem", async () => { - const { strategist, oethbVault, oethb, weth, rafael } = fixture; - - // Add WETH liquidity to allow redeem - await weth - .connect(rafael) - .approve(oethbVault.address, oethUnits("10000")); - await oethbVault - .connect(rafael) - .mint(weth.address, oethUnits("10000"), 0); - - await oethbVault.rebase(); - await _mint(strategist); - - const vaultBalanceBefore = await weth.balanceOf(oethbVault.address); - const userBalanceBefore = await oethb.balanceOf(strategist.address); - const totalSupplyBefore = await oethb.totalSupply(); - - await oethbVault.connect(strategist).redeem(oethUnits("1"), "0"); - - const vaultBalanceAfter = await weth.balanceOf(oethbVault.address); - const userBalanceAfter = await oethb.balanceOf(strategist.address); - const totalSupplyAfter = await oethb.totalSupply(); - - expect(totalSupplyAfter).to.approxEqualTolerance( - totalSupplyBefore.sub(oethUnits("1")) - ); - expect(userBalanceAfter).to.approxEqualTolerance( - userBalanceBefore.sub(oethUnits("1")) - ); - expect(vaultBalanceAfter).to.approxEqualTolerance( - vaultBalanceBefore.sub(oethUnits("1")) - ); - }); - - it("Should allow only Governor to redeem", async () => { - const { governor, oethbVault, oethb, weth, rafael } = fixture; - - // Add WETH liquidity to allow redeem - await weth - .connect(rafael) - .approve(oethbVault.address, oethUnits("10000")); - await oethbVault - .connect(rafael) - .mint(weth.address, oethUnits("10000"), 0); - - await oethbVault.rebase(); - await _mint(governor); - - const vaultBalanceBefore = await weth.balanceOf(oethbVault.address); - const userBalanceBefore = await oethb.balanceOf(governor.address); - const totalSupplyBefore = await oethb.totalSupply(); - - await oethbVault.connect(governor).redeem(oethUnits("1"), "0"); - - const vaultBalanceAfter = await weth.balanceOf(oethbVault.address); - const userBalanceAfter = await oethb.balanceOf(governor.address); - const totalSupplyAfter = await oethb.totalSupply(); - - expect(totalSupplyAfter).to.approxEqualTolerance( - totalSupplyBefore.sub(oethUnits("1")) - ); - expect(userBalanceAfter).to.approxEqualTolerance( - userBalanceBefore.sub(oethUnits("1")) - ); - expect(vaultBalanceAfter).to.approxEqualTolerance( - vaultBalanceBefore.sub(oethUnits("1")) - ); - }); - - it("No one else can redeem", async () => { - const { rafael, nick, oethbVault } = fixture; - - await oethbVault.rebase(); - - for (const signer of [rafael, nick]) { - await _mint(signer); - await expect( - oethbVault.connect(signer).redeem(oethUnits("1"), "0") - ).to.be.revertedWith("Caller is not the Strategist or Governor"); - } - }); }); describe("Async withdrawals", function () { diff --git a/contracts/test/vault/oethb-vault.base.js b/contracts/test/vault/oethb-vault.base.js index 75c55aa396..41c74e8cef 100644 --- a/contracts/test/vault/oethb-vault.base.js +++ b/contracts/test/vault/oethb-vault.base.js @@ -96,17 +96,6 @@ describe("OETHb Vault", function () { .removeStrategyFromMintWhitelist(addresses.dead); await expect(tx).to.be.revertedWith("Not whitelisted"); }); - - describe("Disabled functions", function () { - it("Should not support redeem", async () => { - const { oethbVault, nick } = fixture; - - const tx = oethbVault.connect(nick).redeem(1, 0); - await expect(tx).to.be.revertedWith( - "Caller is not the Strategist or Governor" - ); - }); - }); }); describe("Mint & Burn For Strategy", function () { diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 37cd772451..3214c3c7b8 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -289,13 +289,6 @@ describe("Origin S Vault", function () { fixtureWithUser ); }); - - it("Should not support redeem", async () => { - const { oSonicVault, wS, nick } = fixture; - - const tx = oSonicVault.connect(nick).redeem(wS.address, 1); - await expect(tx).to.be.revertedWith("unsupported function"); - }); }); describe("Administer Sonic Staking Strategy", function () { diff --git a/contracts/test/vault/redeem.js b/contracts/test/vault/redeem.js index 50e4799a84..299fd1b6ac 100644 --- a/contracts/test/vault/redeem.js +++ b/contracts/test/vault/redeem.js @@ -1,17 +1,11 @@ const { expect } = require("chai"); const { loadDefaultFixture } = require("../_fixture"); -const { - ousdUnits, - usdcUnits, - isFork, - expectApproxSupply, - advanceTime, -} = require("../helpers"); +const { ousdUnits, usdcUnits, isFork, advanceTime } = require("../helpers"); const { impersonateAndFund } = require("../../utils/signers"); const { deployWithConfirmation } = require("../../utils/deploy"); -describe("OUSD Vault Redeem", function () { +describe("OUSD Vault Withdrawals", function () { if (isFork) { this.timeout(0); } @@ -21,205 +15,6 @@ describe("OUSD Vault Redeem", function () { fixture = await loadDefaultFixture(); }); - describe("Redeem", function () {}); - - it("Should allow a redeem for strategist", async () => { - const { ousd, vault, usdc, strategist } = fixture; - - await expect(strategist).has.a.balanceOf("1000.00", usdc); - await usdc.connect(strategist).approve(vault.address, usdcUnits("50.0")); - await vault.connect(strategist).mint(usdc.address, usdcUnits("50.0"), 0); - await expect(strategist).has.a.balanceOf("50.00", ousd); - await vault.connect(strategist).redeem(ousdUnits("50.0"), 0); - await expect(strategist).has.a.balanceOf("0.00", ousd); - await expect(strategist).has.a.balanceOf("1000.00", usdc); - expect(await ousd.totalSupply()).to.eq(ousdUnits("200.0")); - - it("Should allow a redeem over the rebase threshold for strategist", async () => { - const { ousd, vault, usdc, strategist, matt } = fixture; - - await expect(strategist).has.a.balanceOf("1000.00", usdc); - - await expect(strategist).has.a.balanceOf("0.00", ousd); - await expect(matt).has.a.balanceOf("100.00", ousd); - - // Strategist mints OUSD with USDC - await usdc - .connect(strategist) - .approve(vault.address, usdcUnits("1000.00")); - await vault - .connect(strategist) - .mint(usdc.address, usdcUnits("1000.00"), 0); - await expect(strategist).has.a.balanceOf("1000.00", ousd); - await expect(matt).has.a.balanceOf("100.00", ousd); - - // Rebase should do nothing - await vault.rebase(); - await expect(strategist).has.a.balanceOf("1000.00", ousd); - await expect(matt).has.a.balanceOf("100.00", ousd); - - // Strategist redeems over the rebase threshold - await vault.connect(strategist).redeem(ousdUnits("500.0"), 0); - await expect(strategist).has.a.approxBalanceOf("500.00", ousd); - await expect(matt).has.a.approxBalanceOf("100.00", ousd); - - // Redeem outputs will be 1000/2200 * 1500 USDC and 1200/2200 * 1500 USDS from fixture - await expect(strategist).has.an.approxBalanceOf("500.00", usdc); - await expectApproxSupply(ousd, ousdUnits("700.0")); - }); - - it("Should have a default redeem fee of 0", async () => { - const { vault } = fixture; - - await expect(await vault.redeemFeeBps()).to.equal("0"); - }); - - // Skipped because OUSD redeem is only available for strategist or governor - // and this is without fees. - it.skip("Should charge a redeem fee if redeem fee set", async () => { - const { ousd, vault, usdc, anna, governor } = fixture; - - // 1000 basis points = 10% - await vault.connect(governor).setRedeemFeeBps(1000); - await expect(anna).has.a.balanceOf("1000.00", usdc); - await usdc.connect(anna).approve(vault.address, usdcUnits("50.0")); - await vault.connect(anna).mint(usdc.address, usdcUnits("50.0"), 0); - await expect(anna).has.a.balanceOf("50.00", ousd); - await vault.connect(anna).redeem(ousdUnits("50.0"), 0); - await expect(anna).has.a.balanceOf("0.00", ousd); - await expect(anna).has.a.balanceOf("995.00", usdc); - }); - - it("Should revert redeem if balance is insufficient", async () => { - const { ousd, vault, usdc, strategist } = fixture; - - // Mint some OUSD tokens - await expect(strategist).has.a.balanceOf("1000.00", usdc); - await usdc.connect(strategist).approve(vault.address, usdcUnits("50.0")); - await vault.connect(strategist).mint(usdc.address, usdcUnits("50.0"), 0); - await expect(strategist).has.a.balanceOf("50.00", ousd); - - // Try to withdraw more than balance - await expect( - vault.connect(strategist).redeem(ousdUnits("100.0"), 0) - ).to.be.revertedWith("Transfer amount exceeds balance"); - }); - - it("Should only allow Governor to set a redeem fee", async () => { - const { vault, anna } = fixture; - - await expect(vault.connect(anna).setRedeemFeeBps(100)).to.be.revertedWith( - "Caller is not the Governor" - ); - }); - - it("Should redeem entire OUSD balance", async () => { - const { ousd, vault, usdc, strategist } = fixture; - - await expect(strategist).has.a.balanceOf("1000.00", usdc); - - // Mint 100 OUSD tokens using USDC - await usdc.connect(strategist).approve(vault.address, usdcUnits("100.0")); - await vault.connect(strategist).mint(usdc.address, usdcUnits("100.0"), 0); - await expect(strategist).has.a.balanceOf("100.00", ousd); - - // Withdraw all - await vault - .connect(strategist) - .redeem(ousd.balanceOf(strategist.address), 0); - - await expect(strategist).has.a.balanceOf("1000", usdc); - }); - - it("Should have correct balances on consecutive mint and redeem", async () => { - const { ousd, vault, usdc, strategist, governor } = fixture; - - const usersWithBalances = [ - [strategist, 0], - [governor, 0], - ]; - - const assetsWithUnits = [[usdc, usdcUnits]]; - - for (const [user, startBalance] of usersWithBalances) { - for (const [asset, units] of assetsWithUnits) { - for (const amount of [5.09, 10.32, 20.99, 100.01]) { - await asset - .connect(user) - .approve(vault.address, await units(amount.toString())); - await vault - .connect(user) - .mint(asset.address, await units(amount.toString()), 0); - await expect(user).has.an.approxBalanceOf( - (startBalance + amount).toString(), - ousd - ); - await vault.connect(user).redeem(ousdUnits(amount.toString()), 0); - await expect(user).has.an.approxBalanceOf( - startBalance.toString(), - ousd - ); - } - } - } - }); - - it("Should correctly handle redeem without a rebase and then full redeem", async function () { - const { ousd, vault, usdc, strategist } = fixture; - await expect(strategist).has.a.balanceOf("0.00", ousd); - await usdc.connect(strategist).mint(usdcUnits("3000.0")); - await usdc - .connect(strategist) - .approve(vault.address, usdcUnits("3000.0")); - await vault - .connect(strategist) - .mint(usdc.address, usdcUnits("3000.0"), 0); - await expect(strategist).has.a.balanceOf("3000.00", ousd); - - //redeem without rebasing (not over threshold) - await vault.connect(strategist).redeem(ousdUnits("200.00"), 0); - //redeem with rebasing (over threshold) - await vault - .connect(strategist) - .redeem(ousd.balanceOf(strategist.address), 0); - - await expect(strategist).has.a.balanceOf("0.00", ousd); - }); - - it("Should respect minimum unit amount argument in redeem", async () => { - const { ousd, vault, usdc, strategist } = fixture; - - await expect(strategist).has.a.balanceOf("1000.00", usdc); - await usdc.connect(strategist).approve(vault.address, usdcUnits("100.0")); - await vault.connect(strategist).mint(usdc.address, usdcUnits("50.0"), 0); - await expect(strategist).has.a.balanceOf("50.00", ousd); - await vault - .connect(strategist) - .redeem(ousdUnits("50.0"), usdcUnits("50")); - await vault.connect(strategist).mint(usdc.address, usdcUnits("50.0"), 0); - await expect( - vault.connect(strategist).redeem(ousdUnits("50.0"), usdcUnits("51")) - ).to.be.revertedWith("Redeem amount lower than minimum"); - }); - - it("Should calculate redeem outputs", async () => { - const { vault, anna, usdc, ousd } = fixture; - - // OUSD total supply is 200 backed by 200 USDC - expect((await vault.calculateRedeemOutputs(ousdUnits("50")))[0]).to.equal( - usdcUnits("50") - ); - - await usdc.connect(anna).approve(vault.address, usdcUnits("600")); - await vault.connect(anna).mint(usdc.address, usdcUnits("600"), 0); - await expect(anna).has.a.balanceOf("600", ousd); - - expect( - (await vault.calculateRedeemOutputs(ousdUnits("100")))[0] - ).to.equal(usdcUnits("100")); - }); - }); - const snapData = async (fixture) => { const { ousd, vault, usdc, user } = fixture; @@ -283,20 +78,17 @@ describe("OUSD Vault Redeem", function () { describe("Withdrawal Queue", function () { const delayPeriod = 10 * 60; // 10 minutes beforeEach(async () => { - const { vault, governor, strategist, josh, matt, usdc } = fixture; - await vault.connect(governor).setWithdrawalClaimDelay(delayPeriod); + const { vault, josh, matt } = fixture; // In the fixture Matt and Josh mint 100 OUSD // We should redeem that first to have only the 60 OUSD from USDC minting - // To do so, we have to make them strategists temporarily - await vault.connect(governor).setStrategistAddr(josh.address); - await vault.connect(josh).redeem(ousdUnits("100"), 0); - await vault.connect(governor).setStrategistAddr(matt.address); - await vault.connect(matt).redeem(ousdUnits("100"), 0); - await vault.connect(governor).setStrategistAddr(strategist.address); - // Then both send usdc to governor to keep internal balance correct - await usdc.connect(josh).transfer(governor.address, usdcUnits("100")); - await usdc.connect(matt).transfer(governor.address, usdcUnits("100")); + await vault.connect(josh).requestWithdrawal(ousdUnits("100")); + await vault.connect(matt).requestWithdrawal(ousdUnits("100")); + + await advanceTime(delayPeriod); // 10 minutes + + await vault.connect(josh).claimWithdrawal(0); + await vault.connect(matt).claimWithdrawal(1); }); describe("with all 60 USDC in the vault", () => { beforeEach(async () => { @@ -337,14 +129,11 @@ describe("OUSD Vault Redeem", function () { .connect(daniel) .requestWithdrawal(firstRequestAmountOUSD); + const queuedAmount = usdcUnits("205"); // 100 + 100 + 5 + await expect(tx) .to.emit(vault, "WithdrawalRequested") - .withArgs( - daniel.address, - 0, - firstRequestAmountOUSD, - firstRequestAmountUSDC - ); + .withArgs(daniel.address, 2, firstRequestAmountOUSD, queuedAmount); await assertChangedData( dataBefore, @@ -371,9 +160,11 @@ describe("OUSD Vault Redeem", function () { const tx = await vault.connect(josh).requestWithdrawal(0); + const queuedAmount = usdcUnits("205"); // 100 + 100 + 5 + await expect(tx) .to.emit(vault, "WithdrawalRequested") - .withArgs(josh.address, 1, 0, firstRequestAmountUSDC); + .withArgs(josh.address, 3, 0, queuedAmount); await assertChangedData( dataBefore, @@ -415,14 +206,11 @@ describe("OUSD Vault Redeem", function () { .connect(matt) .requestWithdrawal(secondRequestAmountOUSD); + const queuedAmount = usdcUnits("223"); // 100 + 100 + 5 + 18 + await expect(tx) .to.emit(vault, "WithdrawalRequested") - .withArgs( - matt.address, - 1, - secondRequestAmountOUSD, - firstRequestAmountUSDC.add(secondRequestAmountUSDC) - ); + .withArgs(matt.address, 3, secondRequestAmountOUSD, queuedAmount); await assertChangedData( dataBefore, @@ -457,14 +245,11 @@ describe("OUSD Vault Redeem", function () { .connect(matt) .requestWithdrawal(secondRequestAmountOUSD); + const queuedAmount = usdcUnits("223"); // 100 + 100 + 5 + 18 + await expect(tx) .to.emit(vault, "WithdrawalRequested") - .withArgs( - matt.address, - 1, - secondRequestAmountOUSD, - firstRequestAmountUSDC.add(secondRequestAmountUSDC) - ); + .withArgs(matt.address, 3, secondRequestAmountOUSD, queuedAmount); await assertChangedData( dataBefore, @@ -492,10 +277,12 @@ describe("OUSD Vault Redeem", function () { const tx = await vault.connect(josh).addWithdrawalQueueLiquidity(); + const claimableAmount = usdcUnits("223"); // 100 + 100 + 5 + 18 + await expect(tx) .to.emit(vault, "WithdrawalClaimable") .withArgs( - firstRequestAmountUSDC.add(secondRequestAmountUSDC), + claimableAmount, firstRequestAmountUSDC.add(secondRequestAmountUSDC) ); @@ -521,20 +308,22 @@ describe("OUSD Vault Redeem", function () { const fixtureWithUser = { ...fixture, user: josh }; await vault.connect(daniel).requestWithdrawal(firstRequestAmountOUSD); await vault.connect(josh).requestWithdrawal(secondRequestAmountOUSD); - const requestId = 1; // ids start at 0 so the second request is at index 1 + const requestId = 3; // ids start at 0 so the fourth request is at index 3. Two in set setup and two here. const dataBefore = await snapData(fixtureWithUser); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. const tx = await vault.connect(josh).claimWithdrawal(requestId); + const claimableAmount = usdcUnits("223"); // 100 + 100 + 5 + 18 + await expect(tx) .to.emit(vault, "WithdrawalClaimed") .withArgs(josh.address, requestId, secondRequestAmountOUSD); await expect(tx) .to.emit(vault, "WithdrawalClaimable") .withArgs( - firstRequestAmountUSDC.add(secondRequestAmountUSDC), + claimableAmount, firstRequestAmountUSDC.add(secondRequestAmountUSDC) ); @@ -564,18 +353,20 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await vault.connect(matt).claimWithdrawals([0, 1]); + const tx = await vault.connect(matt).claimWithdrawals([2, 3]); + + const claimableAmount = usdcUnits("223"); // 100 + 100 + 5 + 18 await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 0, firstRequestAmountOUSD); + .withArgs(matt.address, 2, firstRequestAmountOUSD); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 1, secondRequestAmountOUSD); + .withArgs(matt.address, 3, secondRequestAmountOUSD); await expect(tx) .to.emit(vault, "WithdrawalClaimable") .withArgs( - firstRequestAmountUSDC.add(secondRequestAmountUSDC), + claimableAmount, firstRequestAmountUSDC.add(secondRequestAmountUSDC) ); @@ -616,11 +407,11 @@ describe("OUSD Vault Redeem", function () { const ousdTotalSupply = await ousd.totalSupply(); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await vault.connect(matt).claimWithdrawal(0); // Claim withdrawal for 50% of the supply + const tx = await vault.connect(matt).claimWithdrawal(2); // Claim withdrawal for 50% of the supply await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 0, ousdUnits("30")); + .withArgs(matt.address, 2, ousdUnits("30")); await expect(ousdTotalSupply).to.equal(await ousd.totalSupply()); await expect(totalValueAfter).to.equal(await vault.totalValue()); @@ -632,7 +423,7 @@ describe("OUSD Vault Redeem", function () { // Daniel requests 5 OUSD to be withdrawn await vault.connect(daniel).requestWithdrawal(firstRequestAmountOUSD); - const requestId = 0; + const requestId = 2; // Daniel claimWithdraw request in the same block as the request const tx = vault.connect(daniel).claimWithdrawal(requestId); @@ -664,7 +455,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. // Claim the withdrawal - const tx = vault.connect(daniel).claimWithdrawal(0); + const tx = vault.connect(daniel).claimWithdrawal(2); await expect(tx).to.revertedWith("Backing supply liquidity error"); }); @@ -682,7 +473,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. // Claim the withdrawal - const tx = vault.connect(matt).claimWithdrawals([0, 1]); + const tx = vault.connect(matt).claimWithdrawals([2, 3]); await expect(tx).to.revertedWith("Backing supply liquidity error"); }); @@ -796,11 +587,12 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await vault.connect(daniel).claimWithdrawal(0); + const requestId = 2; + const tx = await vault.connect(daniel).claimWithdrawal(requestId); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(daniel.address, 0, firstRequestAmountOUSD); + .withArgs(daniel.address, requestId, firstRequestAmountOUSD); await assertChangedData( dataBefore, @@ -836,11 +628,12 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await vault.connect(matt).claimWithdrawal(2); + const requestId = 4; + const tx = await vault.connect(matt).claimWithdrawal(requestId); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 2, requestAmount); + .withArgs(matt.address, requestId, requestAmount); await assertChangedData( dataBefore, @@ -868,7 +661,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = vault.connect(matt).claimWithdrawal(2); + const tx = vault.connect(matt).claimWithdrawal(4); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); it("Should claim a new request after withdraw from strategy adds enough liquidity", async () => { @@ -915,7 +708,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await vault.connect(matt).claimWithdrawal(2); + await vault.connect(matt).claimWithdrawal(4); }); it("Should claim a new request after withdrawAllFromStrategy adds enough liquidity", async () => { const { vault, daniel, matt, strategist, usdc } = fixture; @@ -959,7 +752,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await vault.connect(matt).claimWithdrawal(2); + await vault.connect(matt).claimWithdrawal(4); }); it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { const { vault, daniel, matt, strategist, usdc } = fixture; @@ -1001,7 +794,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await vault.connect(matt).claimWithdrawal(2); + await vault.connect(matt).claimWithdrawal(4); }); it("Fail to claim a new request after mint with NOT enough liquidity", async () => { const { vault, daniel, matt, usdc } = fixture; @@ -1021,7 +814,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = vault.connect(matt).claimWithdrawal(2); + const tx = vault.connect(matt).claimWithdrawal(4); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); it("Should claim a new request after mint adds enough liquidity", async () => { @@ -1067,7 +860,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await vault.connect(matt).claimWithdrawal(2); + await vault.connect(matt).claimWithdrawal(4); }); }); @@ -1125,8 +918,8 @@ describe("OUSD Vault Redeem", function () { await vault.connect(daniel).requestWithdrawal(ousdUnits("2")); await vault.connect(josh).requestWithdrawal(ousdUnits("3")); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await vault.connect(daniel).claimWithdrawal(0); - await vault.connect(josh).claimWithdrawal(1); + await vault.connect(daniel).claimWithdrawal(2); + await vault.connect(josh).claimWithdrawal(3); // Deploy a mock strategy mockStrategy = await deployWithConfirmation("MockStrategy"); @@ -1156,7 +949,7 @@ describe("OUSD Vault Redeem", function () { it("a previously claimed withdrawal", async () => { const { vault, daniel } = fixture; - const tx = vault.connect(daniel).claimWithdrawal(0); + const tx = vault.connect(daniel).claimWithdrawal(2); await expect(tx).to.be.revertedWith("Already claimed"); }); @@ -1173,7 +966,7 @@ describe("OUSD Vault Redeem", function () { it("the first withdrawal request in the queue before 30 minutes", async () => { const { vault, daniel } = fixture; - const tx = vault.connect(daniel).claimWithdrawal(2); + const tx = vault.connect(daniel).claimWithdrawal(4); await expect(tx).to.be.revertedWith("Claim delay not met"); }); @@ -1186,7 +979,7 @@ describe("OUSD Vault Redeem", function () { it("Fail to claim the first withdrawal with wrong withdrawer", async () => { const { vault, matt } = fixture; - const tx = vault.connect(matt).claimWithdrawal(2); + const tx = vault.connect(matt).claimWithdrawal(4); await expect(tx).to.be.revertedWith("Not requester"); }); @@ -1195,11 +988,12 @@ describe("OUSD Vault Redeem", function () { const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); - const tx = await vault.connect(daniel).claimWithdrawal(2); + const requestId = 4; + const tx = await vault.connect(daniel).claimWithdrawal(requestId); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(daniel.address, 2, ousdUnits("4")); + .withArgs(daniel.address, requestId, ousdUnits("4")); await assertChangedData( dataBefore, @@ -1221,14 +1015,14 @@ describe("OUSD Vault Redeem", function () { it("Fail to claim the second withdrawal request in the queue after 30 minutes", async () => { const { vault, josh } = fixture; - const tx = vault.connect(josh).claimWithdrawal(3); + const tx = vault.connect(josh).claimWithdrawal(5); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); it("Fail to claim the last (3rd) withdrawal request in the queue", async () => { const { vault, matt } = fixture; - const tx = vault.connect(matt).claimWithdrawal(4); + const tx = vault.connect(matt).claimWithdrawal(6); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); @@ -1248,17 +1042,17 @@ describe("OUSD Vault Redeem", function () { const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); - const tx1 = await vault.connect(daniel).claimWithdrawal(2); + const tx1 = await vault.connect(daniel).claimWithdrawal(4); await expect(tx1) .to.emit(vault, "WithdrawalClaimed") - .withArgs(daniel.address, 2, ousdUnits("4")); + .withArgs(daniel.address, 4, ousdUnits("4")); - const tx2 = await vault.connect(josh).claimWithdrawal(3); + const tx2 = await vault.connect(josh).claimWithdrawal(5); await expect(tx2) .to.emit(vault, "WithdrawalClaimed") - .withArgs(josh.address, 3, ousdUnits("12")); + .withArgs(josh.address, 5, ousdUnits("12")); await assertChangedData( dataBefore, @@ -1430,8 +1224,8 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. // Claim 10 + 20 = 30 USDC from Vault - await vault.connect(daniel).claimWithdrawal(0); - await vault.connect(josh).claimWithdrawal(1); + await vault.connect(daniel).claimWithdrawal(2); + await vault.connect(josh).claimWithdrawal(3); }); it("Should allow the last user to request the remaining 10 USDC", async () => { const { vault, matt } = fixture; @@ -1440,9 +1234,10 @@ describe("OUSD Vault Redeem", function () { const tx = await vault.connect(matt).requestWithdrawal(ousdUnits("10")); + const queuedAmount = usdcUnits("240"); // 110 + 100 + 10 + 20 + 10 await expect(tx) .to.emit(vault, "WithdrawalRequested") - .withArgs(matt.address, 2, ousdUnits("10"), usdcUnits("40")); + .withArgs(matt.address, 4, ousdUnits("10"), queuedAmount); await assertChangedData( dataBefore, @@ -1469,11 +1264,11 @@ describe("OUSD Vault Redeem", function () { const dataBefore = await snapData(fixtureWithUser); - const tx = await vault.connect(matt).claimWithdrawal(2); + const tx = await vault.connect(matt).claimWithdrawal(4); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 2, ousdUnits("10")); + .withArgs(matt.address, 4, ousdUnits("10")); await assertChangedData( dataBefore, @@ -1523,11 +1318,11 @@ describe("OUSD Vault Redeem", function () { const fixtureWithUser = { ...fixture, user: matt }; const dataBefore = await snapData(fixtureWithUser); - const tx = await vault.connect(matt).claimWithdrawal(0); + const tx = await vault.connect(matt).claimWithdrawal(2); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 0, ousdUnits("40")); + .withArgs(matt.address, 2, ousdUnits("40")); await assertChangedData( dataBefore, @@ -1552,13 +1347,13 @@ describe("OUSD Vault Redeem", function () { await vault.connect(josh).requestWithdrawal(ousdUnits("20")); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await vault.connect(josh).claimWithdrawal(1); + const tx = await vault.connect(josh).claimWithdrawal(3); await expect(tx).to.emit(vault, "WithdrawalClaimed"); }); it("Should allow user to perform a new request and claim exactly the USDC available", async () => { const { vault, ousd, josh, matt, daniel } = fixture; - await vault.connect(matt).claimWithdrawal(0); + await vault.connect(matt).claimWithdrawal(2); // All user give OUSD to another user await ousd.connect(josh).transfer(matt.address, ousdUnits("20")); await ousd.connect(daniel).transfer(matt.address, ousdUnits("10")); @@ -1571,11 +1366,11 @@ describe("OUSD Vault Redeem", function () { const dataBefore = await snapData(fixtureWithUser); - const tx = await vault.connect(matt).claimWithdrawal(1); + const tx = await vault.connect(matt).claimWithdrawal(3); await expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(matt.address, 1, ousdUnits("60")); + .withArgs(matt.address, 3, ousdUnits("60")); await assertChangedData( dataBefore, @@ -1596,7 +1391,7 @@ describe("OUSD Vault Redeem", function () { }); it("Shouldn't allow user to perform a new request and claim more than the USDC available", async () => { const { vault, ousd, usdc, josh, matt, daniel, governor } = fixture; - await vault.connect(matt).claimWithdrawal(0); + await vault.connect(matt).claimWithdrawal(2); // All user give OUSD to another user await ousd.connect(josh).transfer(matt.address, ousdUnits("20")); await ousd.connect(daniel).transfer(matt.address, ousdUnits("10")); @@ -1608,7 +1403,7 @@ describe("OUSD Vault Redeem", function () { .connect(await impersonateAndFund(vault.address)) .transfer(governor.address, usdcUnits("50")); // Vault loses 50 USDC - const tx = vault.connect(matt).claimWithdrawal(1); + const tx = vault.connect(matt).claimWithdrawal(3); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); }); @@ -1664,11 +1459,11 @@ describe("OUSD Vault Redeem", function () { const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); - const tx = await vault.connect(daniel).claimWithdrawal(0); + const tx = await vault.connect(daniel).claimWithdrawal(2); expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(daniel.address, 0, ousdUnits("10")); + .withArgs(daniel.address, 2, ousdUnits("10")); await assertChangedData( dataBefore, @@ -1690,7 +1485,7 @@ describe("OUSD Vault Redeem", function () { it("Fail to allow second user to claim the request of 20 USDC, due to liquidity", async () => { const { vault, josh } = fixture; - const tx = vault.connect(josh).claimWithdrawal(1); + const tx = vault.connect(josh).claimWithdrawal(3); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); @@ -1704,7 +1499,7 @@ describe("OUSD Vault Redeem", function () { expect(tx) .to.emit(vault, "WithdrawalRequested") - .withArgs(matt.address, 3, ousdUnits("10"), ousdUnits("50")); + .withArgs(matt.address, 5, ousdUnits("10"), ousdUnits("50")); await assertChangedData( dataBefore, @@ -1743,7 +1538,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); - const tx = vault.connect(daniel).claimWithdrawal(0); + const tx = vault.connect(daniel).claimWithdrawal(2); await expect(tx).to.be.revertedWith("Backing supply liquidity error"); }); @@ -1770,11 +1565,11 @@ describe("OUSD Vault Redeem", function () { it("Should allow first user to claim the request of 10 USDC", async () => { const { vault, daniel } = fixture; - const tx = await vault.connect(daniel).claimWithdrawal(0); + const tx = await vault.connect(daniel).claimWithdrawal(2); expect(tx) .to.emit(vault, "WithdrawalClaimed") - .withArgs(daniel.address, 0, ousdUnits("10")); + .withArgs(daniel.address, 2, ousdUnits("10")); }); }); }); @@ -1858,7 +1653,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); - const tx = vault.connect(daniel).claimWithdrawal(0); + const tx = vault.connect(daniel).claimWithdrawal(2); await expect(tx).to.be.revertedWith("Too many outstanding requests"); }); @@ -1888,7 +1683,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); - const tx = vault.connect(daniel).claimWithdrawal(0); + const tx = vault.connect(daniel).claimWithdrawal(2); await expect(tx).to.be.revertedWith("Too many outstanding requests"); }); @@ -1926,7 +1721,7 @@ describe("OUSD Vault Redeem", function () { await advanceTime(delayPeriod); - const tx = vault.connect(daniel).claimWithdrawal(0); + const tx = vault.connect(daniel).claimWithdrawal(2); // diff = 1 total supply / 0.98 assets = 1.020408163265306122 which is > 1 maxSupplyDiff await expect(tx).to.be.revertedWith("Backing supply liquidity error"); diff --git a/contracts/test/vault/vault.mainnet.fork-test.js b/contracts/test/vault/vault.mainnet.fork-test.js index 0c22bc00ba..95d7d14ac9 100644 --- a/contracts/test/vault/vault.mainnet.fork-test.js +++ b/contracts/test/vault/vault.mainnet.fork-test.js @@ -8,13 +8,11 @@ const { differenceInStrategyBalance, differenceInErc20TokenBalances, isCI, - decimalsFor, } = require("./../helpers"); const { impersonateAndFund } = require("../../utils/signers"); const { shouldHaveRewardTokensConfigured, } = require("./../behaviour/reward-tokens.fork"); -const { formatUnits } = require("ethers/lib/utils"); /** * Regarding hardcoded addresses: @@ -81,27 +79,6 @@ describe("ForkTest: Vault", function () { ).to.be.true; }); - it("Should allow only governor or strategist to redeem", async () => { - const { vault, josh, strategist, usdc, ousd } = fixture; - - await vault.connect(josh).mint(usdc.address, usdcUnits("500"), 0); - - await expect( - vault.connect(josh).redeem(ousdUnits("100"), 0) - ).to.be.revertedWith("Caller is not the Strategist or Governor"); - - // Josh sends OUSD to Strategist - const strategistAddress = await strategist.getAddress(); - await ousd.connect(josh).transfer(strategistAddress, ousdUnits("100")); - - // Strategist redeems successfully - await vault.connect(strategist).redeem(ousdUnits("100"), 0); - - expect(await usdc.balanceOf(strategistAddress)).to.be.equal( - usdcUnits("100") - ); - }); - it("Should have supported assets", async () => { const { vault } = fixture; const assets = await vault.getAllAssets(); @@ -144,30 +121,6 @@ describe("ForkTest: Vault", function () { expect(balanceDiff).to.approxEqualTolerance(ousdUnits("500"), 1); }); - it("Should calculate and return redeem outputs", async () => { - const { vault } = fixture; - const outputs = await vault.calculateRedeemOutputs(ousdUnits("100")); - expect(outputs).to.have.length(1); - const assets = await vault.getAllAssets(); - - const values = await Promise.all( - outputs.map(async (output, index) => { - const asset = await ethers.getContractAt( - "MintableERC20", - assets[index] - ); - return parseFloat( - formatUnits(output.toString(), await decimalsFor(asset)) - ); - }) - ); - - expect(ousdUnits(values[0].toString())).to.approxEqualTolerance( - ousdUnits("100"), - 0.5 - ); - }); - it("should withdraw from and deposit to strategy", async () => { const { vault, josh, usdc, morphoOUSDv2Strategy } = fixture; await vault.connect(josh).mint(usdc.address, usdcUnits("90"), 0); @@ -276,14 +229,6 @@ describe("ForkTest: Vault", function () { } }); - it("Should have correct default strategy set for USDC", async () => { - const { vault, usdc } = fixture; - - expect([ - "0x3643cafA6eF3dd7Fcc2ADaD1cabf708075AFFf6e", //Morpho OUSD v2 Strategy - ]).to.include(await vault.assetDefaultStrategies(usdc.address)); - }); - it("Should be able to withdraw from all strategies", async () => { const { vault, timelock } = fixture; await vault.connect(timelock).withdrawAllFromStrategies(); diff --git a/contracts/test/vault/vault.sonic.fork-test.js b/contracts/test/vault/vault.sonic.fork-test.js index f1deaef205..526f1e1273 100644 --- a/contracts/test/vault/vault.sonic.fork-test.js +++ b/contracts/test/vault/vault.sonic.fork-test.js @@ -79,11 +79,6 @@ describe("ForkTest: Sonic Vault", function () { addresses.multichainBuybackOperator ); }); - - it("Should have redeem fee set to 0.1%", async () => { - const { oSonicVault } = fixture; - expect(await oSonicVault.redeemFeeBps()).to.equal(BigNumber.from("10")); - }); }); describe("Rebase", () => { diff --git a/contracts/test/vault/z_mockvault.js b/contracts/test/vault/z_mockvault.js index cda07c9473..7a21a21206 100644 --- a/contracts/test/vault/z_mockvault.js +++ b/contracts/test/vault/z_mockvault.js @@ -48,10 +48,9 @@ describe("Vault mock with rebase", async () => { utils.parseUnits(`${vaultTotalValue - redeemAmount}`, 18) ); const promise = expect( - mockVault.connect(matt).redeem( - utils.parseUnits(`${redeemAmount}`, 18), - utils.parseUnits(`${redeemAmount}`, 6) // Only USDC in vault. - ) + mockVault + .connect(matt) + .requestWithdrawal(utils.parseUnits(`${redeemAmount}`, 18)) ); if (revertMessage) {