From fc16ad7930f3ab3e58d37300967f54f0afc0b2ce Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Thu, 28 Jul 2022 16:19:35 -0400 Subject: [PATCH 01/16] Replace call to mAPT with one to oracle adapter --- contracts/index/IndexToken.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index 008abea0..4ef72435 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -692,12 +692,12 @@ contract IndexToken is /** * @notice Get the USD value of tokens owed to the pool * @dev Tokens from the pool are typically borrowed by the LP Account - * @dev Tokens borrowed from the pool are tracked with mAPT - * @return The USD value + * @return The USD value. USD prices have 8 decimals. */ function _getDeployedValue() internal view returns (uint256) { - MetaPoolToken mApt = MetaPoolToken(addressRegistry.mAptAddress()); - return mApt.getDeployedValue(address(this)); + IOracleAdapter oracleAdapter = + IOracleAdapter(addressRegistry.oracleAdapterAddress()); + return oracleAdapter.getTvl(); } function _previewRedeem(uint256 shareAmount, bool arbFee) From 558dcdb5aeb50c49b6f935b701898a898a637a23 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 29 Jul 2022 17:56:20 -0400 Subject: [PATCH 02/16] Replace mAPT with lpAccountFunder address --- contracts/index/IndexToken.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index 4ef72435..21be83b1 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -125,7 +125,10 @@ contract IndexToken is _setupRole(DEFAULT_ADMIN_ROLE, addressRegistry.emergencySafeAddress()); _setupRole(ADMIN_ROLE, addressRegistry.adminSafeAddress()); _setupRole(EMERGENCY_ROLE, addressRegistry.emergencySafeAddress()); - _setupRole(CONTRACT_ROLE, addressRegistry.mAptAddress()); + _setupRole( + CONTRACT_ROLE, + addressRegistry.getAddress("lpAccountFunder") + ); arbitrageFeePeriod = 1 days; arbitrageFee = 5; From d96f4c998a6a3afccbd4a41c9f125e43e74cd049 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 29 Jul 2022 18:23:31 -0400 Subject: [PATCH 03/16] Update unit tests --- test-unit/IndexToken.js | 87 ++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/test-unit/IndexToken.js b/test-unit/IndexToken.js index bd7bc6d1..77fe1c8f 100644 --- a/test-unit/IndexToken.js +++ b/test-unit/IndexToken.js @@ -10,12 +10,11 @@ const { ZERO_ADDRESS, FAKE_ADDRESS, tokenAmountToBigNumber, - impersonateAccount, + bytes32, } = require("../utils/helpers"); const IDetailedERC20 = artifacts.require("IDetailedERC20"); const AddressRegistry = artifacts.require("IAddressRegistryV2"); -const MetaPoolToken = artifacts.require("MetaPoolToken"); const OracleAdapter = artifacts.require("OracleAdapter"); describe("Contract: IndexToken", () => { @@ -23,7 +22,7 @@ describe("Contract: IndexToken", () => { let deployer; let adminSafe; let emergencySafe; - let mApt; + let lpAccountFunder; let lpAccount; let lpSafe; let randomUser; @@ -33,7 +32,6 @@ describe("Contract: IndexToken", () => { // mocks let assetMock; let addressRegistryMock; - let mAptMock; let oracleAdapterMock; // pool @@ -57,6 +55,7 @@ describe("Contract: IndexToken", () => { [ deployer, lpAccount, + lpAccountFunder, adminSafe, emergencySafe, lpSafe, @@ -76,8 +75,9 @@ describe("Contract: IndexToken", () => { AddressRegistry.abi ); - mAptMock = await deployMockContract(deployer, MetaPoolToken.abi); - await addressRegistryMock.mock.mAptAddress.returns(mAptMock.address); + await addressRegistryMock.mock.getAddress + .withArgs(bytes32("lpAccountFunder")) + .returns(lpAccountFunder.address); oracleAdapterMock = await deployMockContract(deployer, OracleAdapter.abi); await addressRegistryMock.mock.oracleAdapterAddress.returns( @@ -91,8 +91,6 @@ describe("Contract: IndexToken", () => { emergencySafe.address ); - mApt = await impersonateAccount(mAptMock.address, 10); - const IndexToken = await ethers.getContractFactory("TestIndexToken"); logic = await IndexToken.deploy(); await logic.deployed(); @@ -148,11 +146,12 @@ describe("Contract: IndexToken", () => { .true; }); - it("Contract role given to mAPT", async () => { + it("Contract role given to LP Account Funder", async () => { const CONTRACT_ROLE = await indexToken.CONTRACT_ROLE(); const memberCount = await indexToken.getRoleMemberCount(CONTRACT_ROLE); expect(memberCount).to.equal(1); - expect(await indexToken.hasRole(CONTRACT_ROLE, mApt.address)).to.be.true; + expect(await indexToken.hasRole(CONTRACT_ROLE, lpAccountFunder.address)) + .to.be.true; }); it("Emergency role given to Emergency Safe", async () => { @@ -310,23 +309,23 @@ describe("Contract: IndexToken", () => { ).to.revertedWith("Pausable: paused"); }); - it("Revert when calling transferToLpAccount on locked pool from mAPT", async () => { + it("Revert when calling transferToLpAccount on locked pool from LP Account Funder", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( - indexToken.connect(mApt).transferToLpAccount(100) + indexToken.connect(lpAccountFunder).transferToLpAccount(100) ).to.revertedWith("Pausable: paused"); }); }); - describe("Transfer to LP Safe", () => { + describe("Transfer to LP Account", () => { before(async () => { await assetMock.mock.transfer.returns(true); }); - it("mAPT can call transferToLpAccount", async () => { - await expect(indexToken.connect(mApt).transferToLpAccount(100)).to.not.be - .reverted; + it("LP Account Funder can call transferToLpAccount", async () => { + await expect(indexToken.connect(lpAccountFunder).transferToLpAccount(100)) + .to.not.be.reverted; }); it("Revert when unpermissioned account calls transferToLpAccount", async () => { @@ -417,35 +416,29 @@ describe("Contract: IndexToken", () => { const expectedValue = balance.mul(price).div(10 ** decimals); // force zero deployed value - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); expect(await indexToken.testGetDeployedValue()).to.equal(0); expect(await indexToken.testGetPoolAssetValue()).to.equal(expectedValue); // force non-zero deployed value - await mAptMock.mock.getDeployedValue.returns(1234); + await oracleAdapterMock.mock.getTvl.returns(1234); expect(await indexToken.testGetDeployedValue()).to.be.gt(0); expect(await indexToken.testGetPoolAssetValue()).to.equal(expectedValue); }); }); describe("_getDeployedValue", () => { - it("Delegates properly to mAPT contract", async () => { - await mAptMock.mock.getDeployedValue - .withArgs(indexToken.address) - .returns(0); + it("Delegates properly to Oracle Adapter", async () => { + await oracleAdapterMock.mock.getTvl.returns(0); expect(await indexToken.testGetDeployedValue()).to.equal(0); const deployedValue = tokenAmountToBigNumber(12345); - await mAptMock.mock.getDeployedValue - .withArgs(indexToken.address) - .returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); expect(await indexToken.testGetDeployedValue()).to.equal(deployedValue); }); it("Reverts with same reason when mAPT reverts", async () => { - await mAptMock.mock.getDeployedValue - .withArgs(indexToken.address) - .revertsWithReason("SOMETHING_WRONG"); + await oracleAdapterMock.mock.getTvl.revertsWithReason("SOMETHING_WRONG"); await expect(indexToken.testGetDeployedValue()).to.be.revertedWith( "SOMETHING_WRONG" ); @@ -460,7 +453,7 @@ describe("Contract: IndexToken", () => { await assetMock.mock.balanceOf.returns(assetBalance); const deployedValue = tokenAmountToBigNumber(1234); - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const price = 2; await oracleAdapterMock.mock.getAssetPrice.returns(price); @@ -497,14 +490,14 @@ describe("Contract: IndexToken", () => { const aptAmount = tokenAmountToBigNumber(10); // zero deployed value - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); let poolTotalValue = await indexToken.getPoolTotalValue(); let expectedValue = poolTotalValue.mul(aptAmount).div(aptSupply); expect(await indexToken.getUsdValue(aptAmount)).to.equal(expectedValue); // non-zero deployed value const deployedValue = tokenAmountToBigNumber(1234); - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); poolTotalValue = await indexToken.getPoolTotalValue(); expectedValue = poolTotalValue.mul(aptAmount).div(aptSupply); expect(await indexToken.getUsdValue(aptAmount)).to.equal(expectedValue); @@ -515,7 +508,7 @@ describe("Contract: IndexToken", () => { it("Returns 0 when pool has zero total value", async () => { // set pool total ETH value to 0 await oracleAdapterMock.mock.getAssetPrice.returns(1); - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); await assetMock.mock.balanceOf.returns(0); await assetMock.mock.decimals.returns(6); @@ -524,7 +517,7 @@ describe("Contract: IndexToken", () => { it("Returns correctly calculated value when zero deployed value", async () => { await oracleAdapterMock.mock.getAssetPrice.returns(1); - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); // set positive pool asset ETH value, // which should result in negative reserve top-up const decimals = 6; @@ -557,7 +550,7 @@ describe("Contract: IndexToken", () => { await indexToken.testMint(deployer.address, aptSupply); const deployedValue = tokenAmountToBigNumber(1000); - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const topUpAmount = await indexToken.getReserveTopUpValue(); const topUpValue = topUpAmount.mul(price).div(10 ** decimals); @@ -585,7 +578,7 @@ describe("Contract: IndexToken", () => { await indexToken.testMint(deployer.address, aptSupply); const deployedValue = tokenAmountToBigNumber(500); - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const poolAssetValue = await indexToken.testGetPoolAssetValue(); const topUpAmount = await indexToken.getReserveTopUpValue(); @@ -616,7 +609,7 @@ describe("Contract: IndexToken", () => { await indexToken.testMint(deployer.address, aptSupply); const deployedValue = tokenAmountToBigNumber(20); - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const poolAssetValue = await indexToken.testGetPoolAssetValue(); const topUpAmount = await indexToken.getReserveTopUpValue(); @@ -638,7 +631,7 @@ describe("Contract: IndexToken", () => { describe("convertToShares", () => { beforeEach(async () => { - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); }); it("Uses 1:1 token ratio with zero total supply", async () => { @@ -665,7 +658,7 @@ describe("Contract: IndexToken", () => { ); // result doesn't depend on pool's deployed value - await mAptMock.mock.getDeployedValue.returns(10000000); + await oracleAdapterMock.mock.getTvl.returns(10000000); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedShareAmount ); @@ -703,9 +696,7 @@ describe("Contract: IndexToken", () => { await assetMock.mock.balanceOf.returns(poolAssetBalance); await assetMock.mock.decimals.returns(decimals); - await mAptMock.mock.balanceOf.returns(tokenAmountToBigNumber(10)); - await mAptMock.mock.totalSupply.returns(tokenAmountToBigNumber(1000)); - await mAptMock.mock.getDeployedValue.returns( + await oracleAdapterMock.mock.getTvl.returns( tokenAmountToBigNumber(10000000) ); @@ -724,7 +715,7 @@ describe("Contract: IndexToken", () => { describe("convertToAssets", () => { beforeEach(async () => { - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); }); it("Convert 1:1 on zero total supply", async () => { @@ -881,7 +872,7 @@ describe("Contract: IndexToken", () => { beforeEach(async () => { // These get rollbacked due to snapshotting. // Just enough mocking to get `deposit` to not revert. - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); await oracleAdapterMock.mock.getAssetPrice.returns(1); await assetMock.mock.decimals.returns(6); await assetMock.mock.allowance.returns(1); @@ -995,7 +986,7 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); @@ -1146,7 +1137,7 @@ describe("Contract: IndexToken", () => { beforeEach(async () => { // These get rollbacked due to snapshotting. // Just enough mocking to get `mint` to not revert. - await mAptMock.mock.getDeployedValue.returns(0); + await oracleAdapterMock.mock.getTvl.returns(0); await oracleAdapterMock.mock.getAssetPrice.returns(1); await assetMock.mock.decimals.returns(6); await assetMock.mock.allowance.returns(2); // account for rounding up in previewMint @@ -1208,7 +1199,7 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); @@ -1332,7 +1323,7 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); @@ -1547,7 +1538,7 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await mAptMock.mock.getDeployedValue.returns(deployedValue); + await oracleAdapterMock.mock.getTvl.returns(deployedValue); const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); From a03f552ba5b6d2d9de15c38ba4b0fef55f6965e3 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Mon, 1 Aug 2022 10:56:18 -0400 Subject: [PATCH 04/16] Start int test cleanup --- test-integration/IndexToken.js | 70 ++++++++++++++-------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/test-integration/IndexToken.js b/test-integration/IndexToken.js index cd0f6a5b..560ccf1c 100644 --- a/test-integration/IndexToken.js +++ b/test-integration/IndexToken.js @@ -1,7 +1,7 @@ const { assert, expect } = require("chai"); const { ethers } = require("hardhat"); const { AddressZero: ZERO_ADDRESS, MaxUint256: MAX_UINT256 } = ethers.constants; -const { impersonateAccount, bytes32 } = require("../utils/helpers"); +const { bytes32 } = require("../utils/helpers"); const timeMachine = require("ganache-time-traveler"); const { WHALE_POOLS, FARM_TOKENS } = require("../utils/constants"); const { @@ -21,7 +21,12 @@ const link = (amount) => tokenAmountToBigNumber(amount, "18"); console.debugging = false; /* ************************ */ -describe("Contract: IndexToken", () => { + const vaultAssetSymbol = "USDC"; + const vaultAssetAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; + // use usdc agg for now + const vaultAggAddress = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"; + +describe.only("Contract: IndexToken", () => { let deployer; let oracle; let adminSafe; @@ -30,6 +35,14 @@ describe("Contract: IndexToken", () => { let anotherUser; let receiver; + + let tvlAgg; + let asset; + let oracleAdapter; + let lpAccountFunder; + let addressRegistry; + let indexToken; + before(async () => { [ deployer, @@ -39,6 +52,7 @@ describe("Contract: IndexToken", () => { randomUser, anotherUser, receiver, + lpAccountFunder, ] = await ethers.getSigners(); }); @@ -64,19 +78,9 @@ describe("Contract: IndexToken", () => { await timeMachine.revertToSnapshot(suiteSnapshotId); }); - const symbol = "USDC"; - const tokenAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; - const USDC_AGG_ADDRESS = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"; - - let tvlAgg; - let asset; - let oracleAdapter; - let mApt; - let addressRegistry; - let indexToken; before("Setup", async () => { - asset = await ethers.getContractAt("IDetailedERC20", tokenAddress); + asset = await ethers.getContractAt("IDetailedERC20", vaultAssetAddress); const paymentAmount = link("1"); const maxSubmissionValue = tokenAmountToBigNumber("1", "20"); @@ -155,30 +159,18 @@ describe("Contract: IndexToken", () => { const proxyAdmin = await ProxyAdmin.deploy(); await proxyAdmin.deployed(); - const MetaPoolToken = await ethers.getContractFactory("TestMetaPoolToken"); - const mAptLogic = await MetaPoolToken.deploy(); - await mAptLogic.deployed(); + await addressRegistry.registerAddress(bytes32("lpAccountFunder"), lpAccountFunder.address); - const mAptInitData = MetaPoolToken.interface.encodeFunctionData( - "initialize(address)", - [addressRegistry.address] - ); - const mAptProxy = await TransparentUpgradeableProxy.deploy( - mAptLogic.address, - proxyAdmin.address, - mAptInitData - ); - await mAptProxy.deployed(); - mApt = await MetaPoolToken.attach(mAptProxy.address); - - await addressRegistry.registerAddress(bytes32("mApt"), mApt.address); + // dummy address needed for oracle adapter deploy + const mAptAddress = await generateContractAddress(deployer) + await addressRegistry.registerAddress(bytes32("mApt"), mAptAddress); const OracleAdapter = await ethers.getContractFactory("OracleAdapter"); oracleAdapter = await OracleAdapter.deploy( addressRegistry.address, tvlAgg.address, - [tokenAddress], - [USDC_AGG_ADDRESS], + [vaultAssetAddress], + [vaultAggAddress], 86400, 86400 ); @@ -206,7 +198,7 @@ describe("Contract: IndexToken", () => { indexToken = await IndexToken.attach(proxy.address); await acquireToken( - WHALE_POOLS[symbol], + WHALE_POOLS[vaultAssetSymbol], randomUser.address, asset, "1000000", @@ -334,14 +326,10 @@ describe("Contract: IndexToken", () => { }); }); - describe("Transfer to LP Account", () => { - it("mAPT can call transferToLpAccount", async () => { - // need to impersonate the mAPT contract and fund it, since its - // address was set as CONTRACT_ROLE upon PoolTokenV2 deployment - const mAptSigner = await impersonateAccount(mApt.address); - + describe.only("Transfer to LP Account", () => { + it("LP Account Funder can call transferToLpAccount", async () => { await indexToken.connect(randomUser).deposit(100, receiver.address); - await expect(indexToken.connect(mAptSigner).transferToLpAccount(100)).to + await expect(indexToken.connect(lpAccountFunder).transferToLpAccount(100)).to .not.be.reverted; }); @@ -1067,7 +1055,7 @@ describe("Contract: IndexToken", () => { ); // seed pool with stablecoin await acquireToken( - WHALE_POOLS[symbol], + WHALE_POOLS[vaultAssetSymbol], indexToken.address, asset, "12000000", // 12 MM @@ -1103,7 +1091,7 @@ describe("Contract: IndexToken", () => { ); // seed pool with stablecoin await acquireToken( - WHALE_POOLS[symbol], + WHALE_POOLS[vaultAssetSymbol], indexToken.address, asset, "12000000", // 12 MM From 4cb702f28080f8059bbba7ff5b2e6dbc34588c4b Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Mon, 1 Aug 2022 10:56:53 -0400 Subject: [PATCH 05/16] Fix deployed value tests --- test-integration/IndexToken.js | 48 +++++++++------------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/test-integration/IndexToken.js b/test-integration/IndexToken.js index 560ccf1c..2d5d4801 100644 --- a/test-integration/IndexToken.js +++ b/test-integration/IndexToken.js @@ -21,10 +21,10 @@ const link = (amount) => tokenAmountToBigNumber(amount, "18"); console.debugging = false; /* ************************ */ - const vaultAssetSymbol = "USDC"; - const vaultAssetAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; - // use usdc agg for now - const vaultAggAddress = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"; +const vaultAssetSymbol = "USDC"; +const vaultAssetAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; +// use usdc agg for now +const vaultAggAddress = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"; describe.only("Contract: IndexToken", () => { let deployer; @@ -35,7 +35,6 @@ describe.only("Contract: IndexToken", () => { let anotherUser; let receiver; - let tvlAgg; let asset; let oracleAdapter; @@ -78,7 +77,6 @@ describe.only("Contract: IndexToken", () => { await timeMachine.revertToSnapshot(suiteSnapshotId); }); - before("Setup", async () => { asset = await ethers.getContractAt("IDetailedERC20", vaultAssetAddress); @@ -159,10 +157,13 @@ describe.only("Contract: IndexToken", () => { const proxyAdmin = await ProxyAdmin.deploy(); await proxyAdmin.deployed(); - await addressRegistry.registerAddress(bytes32("lpAccountFunder"), lpAccountFunder.address); + await addressRegistry.registerAddress( + bytes32("lpAccountFunder"), + lpAccountFunder.address + ); // dummy address needed for oracle adapter deploy - const mAptAddress = await generateContractAddress(deployer) + const mAptAddress = await generateContractAddress(deployer); await addressRegistry.registerAddress(bytes32("mApt"), mAptAddress); const OracleAdapter = await ethers.getContractFactory("OracleAdapter"); @@ -326,11 +327,11 @@ describe.only("Contract: IndexToken", () => { }); }); - describe.only("Transfer to LP Account", () => { + describe("Transfer to LP Account", () => { it("LP Account Funder can call transferToLpAccount", async () => { await indexToken.connect(randomUser).deposit(100, receiver.address); - await expect(indexToken.connect(lpAccountFunder).transferToLpAccount(100)).to - .not.be.reverted; + await expect(indexToken.connect(lpAccountFunder).transferToLpAccount(100)) + .to.not.be.reverted; }); it("Revert when unpermissioned account calls transferToLpAccount", async () => { @@ -461,8 +462,6 @@ describe.only("Contract: IndexToken", () => { ]; deployedValues.forEach(function (deployedValue) { describe(`Deployed value: ${deployedValue}`, () => { - const mAptSupply = tokenAmountToBigNumber("100"); - async function updateTvlAgg(usdDeployedValue) { if (usdDeployedValue.isZero()) { await oracleAdapter.connect(emergencySafe).emergencySetTvl(0, 100); @@ -476,7 +475,6 @@ describe.only("Contract: IndexToken", () => { /* these get rollbacked after each test due to snapshotting */ // default to giving entire deployed value to the pool - await mApt.testMint(indexToken.address, mAptSupply); await updateTvlAgg(deployedValue); await oracleAdapter.connect(emergencySafe).emergencyUnlock(); }); @@ -575,28 +573,6 @@ describe.only("Contract: IndexToken", () => { expect(await indexToken.testGetDeployedValue()).to.equal( deployedValue ); - - // transfer quarter of mAPT to another pool - await mApt.testMint(FAKE_ADDRESS, mAptSupply.div(4)); - await mApt.testBurn(indexToken.address, mAptSupply.div(4)); - // unlock oracle adapter after mint/burn - await oracleAdapter.connect(emergencySafe).emergencyUnlock(); - // must update agg so staleness check passes - await updateTvlAgg(deployedValue); - expect(await indexToken.testGetDeployedValue()).to.equal( - deployedValue.mul(3).div(4) - ); - - // transfer same amount again - await mApt.testMint(FAKE_ADDRESS, mAptSupply.div(4)); - await mApt.testBurn(indexToken.address, mAptSupply.div(4)); - // unlock oracle adapter after mint/burn - await oracleAdapter.connect(emergencySafe).emergencyUnlock(); - // must update agg so staleness check passes - await updateTvlAgg(deployedValue); - expect(await indexToken.testGetDeployedValue()).to.equal( - deployedValue.div(2) - ); }); it("getReserveTopUpValue returns correct value", async () => { From 3389a57c6af690d8ce57c85924d360aa196639d2 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Mon, 1 Aug 2022 11:02:00 -0400 Subject: [PATCH 06/16] Add check to retain old functionality --- contracts/index/IndexToken.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index 21be83b1..3fc7915d 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -698,6 +698,8 @@ contract IndexToken is * @return The USD value. USD prices have 8 decimals. */ function _getDeployedValue() internal view returns (uint256) { + if (totalSupply() == 0) return 0; + IOracleAdapter oracleAdapter = IOracleAdapter(addressRegistry.oracleAdapterAddress()); return oracleAdapter.getTvl(); From 1ccffef9206e7be74033a5e1b61fcadb6480ff7d Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Mon, 1 Aug 2022 15:49:52 -0400 Subject: [PATCH 07/16] Fix redeem unlock test --- test-integration/IndexToken.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test-integration/IndexToken.js b/test-integration/IndexToken.js index 2d5d4801..2efff807 100644 --- a/test-integration/IndexToken.js +++ b/test-integration/IndexToken.js @@ -380,6 +380,7 @@ describe.only("Contract: IndexToken", () => { await indexToken.connect(emergencySafe).emergencyUnlockRedeem(); await indexToken.testMint(randomUser.address, 1); + await oracleAdapter.connect(emergencySafe).emergencySetTvl(0, 100); await expect( indexToken .connect(randomUser) From ea0a7d78f583d5b82e86c6976ac191021240f329 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Wed, 3 Aug 2022 13:13:16 -0400 Subject: [PATCH 08/16] Rename pool to vault --- .../index/{IFeePool.sol => IFeeVault.sol} | 4 +- .../{ILockingPool.sol => ILockingVault.sol} | 4 +- contracts/index/IReservePool.sol | 6 +- contracts/index/IReserveVault.sol | 39 ++++++++++++ contracts/index/Imports.sol | 6 +- contracts/index/IndexToken.sol | 62 +++++++++---------- contracts/index/TestIndexToken.sol | 4 +- 7 files changed, 81 insertions(+), 44 deletions(-) rename contracts/index/{IFeePool.sol => IFeeVault.sol} (96%) rename contracts/index/{ILockingPool.sol => ILockingVault.sol} (90%) create mode 100644 contracts/index/IReserveVault.sol diff --git a/contracts/index/IFeePool.sol b/contracts/index/IFeeVault.sol similarity index 96% rename from contracts/index/IFeePool.sol rename to contracts/index/IFeeVault.sol index a4cce388..0469d35e 100644 --- a/contracts/index/IFeePool.sol +++ b/contracts/index/IFeeVault.sol @@ -2,9 +2,9 @@ pragma solidity 0.6.11; /** - * @notice For pools that can charge an early withdraw fee + * @notice For vaults that can charge an early withdraw fee */ -interface IFeePool { +interface IFeeVault { /** * @notice Log when the arbitrage fee period changes * @param arbitrageFeePeriod The new period diff --git a/contracts/index/ILockingPool.sol b/contracts/index/ILockingVault.sol similarity index 90% rename from contracts/index/ILockingPool.sol rename to contracts/index/ILockingVault.sol index ba523e67..7e43fede 100644 --- a/contracts/index/ILockingPool.sol +++ b/contracts/index/ILockingVault.sol @@ -2,9 +2,9 @@ pragma solidity 0.6.11; /** - * @notice For pools that can be locked and unlocked in emergencies + * @notice For vaults that can be locked and unlocked in emergencies */ -interface ILockingPool { +interface ILockingVault { /** @notice Log when deposits are locked */ event DepositLocked(); diff --git a/contracts/index/IReservePool.sol b/contracts/index/IReservePool.sol index 3829375b..02c29354 100644 --- a/contracts/index/IReservePool.sol +++ b/contracts/index/IReservePool.sol @@ -2,9 +2,9 @@ pragma solidity 0.6.11; /** - * @notice For pools that keep a separate reserve of tokens + * @notice For vaults that keep a separate reserve of tokens */ -interface IReservePool { +interface IReserveVault { /** * @notice Log when the percent held in reserve is changed * @param reservePercentage The new percent held in reserve @@ -19,7 +19,7 @@ interface IReservePool { /** * @notice Transfer an amount of tokens to the LP Account - * @dev This should only be callable by the `MetaPoolToken` + * @dev This should only be callable by the `LpAccountFunder` * @param amount The amount of tokens */ function transferToLpAccount(uint256 amount) external; diff --git a/contracts/index/IReserveVault.sol b/contracts/index/IReserveVault.sol new file mode 100644 index 00000000..02c29354 --- /dev/null +++ b/contracts/index/IReserveVault.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BUSDL-1.1 +pragma solidity 0.6.11; + +/** + * @notice For vaults that keep a separate reserve of tokens + */ +interface IReserveVault { + /** + * @notice Log when the percent held in reserve is changed + * @param reservePercentage The new percent held in reserve + */ + event ReservePercentageChanged(uint256 reservePercentage); + + /** + * @notice Set a new percent of tokens to hold in reserve + * @param reservePercentage_ The new percent + */ + function setReservePercentage(uint256 reservePercentage_) external; + + /** + * @notice Transfer an amount of tokens to the LP Account + * @dev This should only be callable by the `LpAccountFunder` + * @param amount The amount of tokens + */ + function transferToLpAccount(uint256 amount) external; + + /** + * @notice Get the amount of tokens missing from the reserve + * @dev A negative amount indicates extra tokens not needed for the reserve + * @return The amount of missing tokens + */ + function getReserveTopUpValue() external view returns (int256); + + /** + * @notice Get the current percentage of tokens held in reserve + * @return The percent + */ + function reservePercentage() external view returns (uint256); +} diff --git a/contracts/index/Imports.sol b/contracts/index/Imports.sol index 45909bb4..5045f79f 100644 --- a/contracts/index/Imports.sol +++ b/contracts/index/Imports.sol @@ -2,6 +2,6 @@ pragma solidity 0.6.11; import {IERC4626} from "./IERC4626.sol"; -import {IFeePool} from "./IFeePool.sol"; -import {ILockingPool} from "./ILockingPool.sol"; -import {IReservePool} from "./IReservePool.sol"; +import {IFeeVault} from "./IFeeVault.sol"; +import {ILockingVault} from "./ILockingVault.sol"; +import {IReserveVault} from "./IReserveVault.sol"; diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index 3fc7915d..eac94e30 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -19,24 +19,22 @@ import { AggregatorV3Interface, IOracleAdapter } from "contracts/oracle/Imports.sol"; -import {MetaPoolToken} from "contracts/mapt/MetaPoolToken.sol"; -import {IERC4626, IFeePool, ILockingPool, IReservePool} from "./Imports.sol"; +import {IERC4626, IFeeVault, ILockingVault, IReserveVault} from "./Imports.sol"; /** * @notice Collect user deposits so they can be lent to the LP Account - * @notice Depositors share pool liquidity + * @notice Depositors share vault liquidity * @notice Reserves are maintained to process withdrawals * @notice Reserve tokens cannot be lent to the LP Account * @notice If a user withdraws too early after their deposit, there's a fee - * @notice Tokens borrowed from the pool are tracked with the `MetaPoolToken` */ contract IndexToken is IERC4626, IEmergencyExit, - IFeePool, - ILockingPool, - IReservePool, + IFeeVault, + ILockingVault, + IReserveVault, Initializable, AccessControlUpgradeSafe, ReentrancyGuardUpgradeSafe, @@ -81,7 +79,7 @@ contract IndexToken is */ uint256 public override withdrawFee; - /** @notice percentage of pool total value available for immediate withdrawal */ + /** @notice percentage of vault total value available for immediate withdrawal */ uint256 public override reservePercentage; /* ------------------------------- */ @@ -238,7 +236,7 @@ contract IndexToken is } /** - * @dev May revert if there is not enough in the pool. + * @dev May revert if there is not enough in the vault. */ function redeem( uint256 shares, @@ -404,7 +402,7 @@ contract IndexToken is function getUsdValue(uint256 shareAmount) external view returns (uint256) { if (shareAmount == 0) return 0; require(totalSupply() > 0, "INSUFFICIENT_TOTAL_SUPPLY"); - return shareAmount.mul(getPoolTotalValue()).div(totalSupply()); + return shareAmount.mul(getVaultTotalValue()).div(totalSupply()); } function getReserveTopUpValue() external view override returns (int256) { @@ -532,11 +530,11 @@ contract IndexToken is } /** - * @dev Total value also includes that have been borrowed from the pool - * @dev Typically it is the LP Account that borrows from the pool + * @dev Total value also includes that have been borrowed from the vault + * @dev Typically it is the LP Account that borrows from the vault */ - function getPoolTotalValue() public view returns (uint256) { - uint256 assetValue = _getPoolAssetValue(); + function getVaultTotalValue() public view returns (uint256) { + uint256 assetValue = _getVaultAssetValue(); uint256 mAptValue = _getDeployedValue(); return assetValue.add(mAptValue); } @@ -561,10 +559,10 @@ contract IndexToken is /** * @dev amount of share minted should be in same ratio to share supply - * as deposit value is to pool's total value, i.e.: + * as deposit value is to vault's total value, i.e.: * * mint amount / total supply - * = deposit value / pool total value + * = deposit value / vault total value * * For denominators, pre or post-deposit amounts can be used. * The important thing is they are consistent, i.e. both pre-deposit @@ -584,7 +582,7 @@ contract IndexToken is // mathematically equivalent to: // assets.mul(supply).div(totalAssets()) // but better precision due to avoiding early division - uint256 totalValue = getPoolTotalValue(); + uint256 totalValue = getVaultTotalValue(); uint256 assetPrice = getAssetPrice(); return assets.mul(supply).mul(assetPrice).div(totalValue).div( @@ -608,7 +606,7 @@ contract IndexToken is // mathematically equivalent to: // shares.mul(totalAssets()).div(supply) // but better precision due to avoiding early division - uint256 totalValue = getPoolTotalValue(); + uint256 totalValue = getVaultTotalValue(); uint256 assetPrice = getAssetPrice(); return shares.mul(totalValue).mul(10**decimals).div(assetPrice).div( @@ -617,7 +615,7 @@ contract IndexToken is } function totalAssets() public view virtual override returns (uint256) { - uint256 totalValue = getPoolTotalValue(); + uint256 totalValue = getVaultTotalValue(); uint256 assetPrice = getAssetPrice(); uint256 decimals = IDetailedERC20(asset).decimals(); return totalValue.mul(10**decimals).div(assetPrice); @@ -632,21 +630,21 @@ contract IndexToken is /** * @dev This "top-up" value should satisfy: * - * top-up USD value + pool underlyer USD value - * = (reserve %) * pool deployed value (after unwinding) + * top-up USD value + vault underlyer USD value + * = (reserve %) * vault deployed value (after unwinding) * - * @dev Taking the percentage of the pool's current deployed value + * @dev Taking the percentage of the vault's current deployed value * is not sufficient, because the requirement is to have the * resulting values after unwinding capital satisfy the * above equation. * * More precisely: * - * R_pre = pool underlyer USD value before pushing unwound - * capital to the pool - * R_post = pool underlyer USD value after pushing - * DV_pre = pool's deployed USD value before unwinding - * DV_post = pool's deployed USD value after unwinding + * R_pre = vault underlyer USD value before pushing unwound + * capital to the vault + * R_post = vault underlyer USD value after pushing + * DV_pre = vault's deployed USD value before unwinding + * DV_post = vault's deployed USD value after unwinding * rPerc = the reserve percentage as a whole number * out of 100 * @@ -664,7 +662,7 @@ contract IndexToken is function _getReserveTopUpValue() internal view returns (int256) { uint256 unnormalizedTargetValue = _getDeployedValue().mul(reservePercentage); - uint256 unnormalizedAssetValue = _getPoolAssetValue().mul(100); + uint256 unnormalizedAssetValue = _getVaultAssetValue().mul(100); require( unnormalizedTargetValue <= uint256(type(int256).max), @@ -682,10 +680,10 @@ contract IndexToken is } /** - * @notice Get the USD value of tokens in the pool + * @notice Get the USD value of tokens in the vault * @return The USD value */ - function _getPoolAssetValue() internal view returns (uint256) { + function _getVaultAssetValue() internal view returns (uint256) { return getValueFromAssetAmount( IDetailedERC20(asset).balanceOf(address(this)) @@ -693,8 +691,8 @@ contract IndexToken is } /** - * @notice Get the USD value of tokens owed to the pool - * @dev Tokens from the pool are typically borrowed by the LP Account + * @notice Get the USD value of tokens owed to the vault + * @dev Tokens from the vault are typically borrowed by the LP Account * @return The USD value. USD prices have 8 decimals. */ function _getDeployedValue() internal view returns (uint256) { diff --git a/contracts/index/TestIndexToken.sol b/contracts/index/TestIndexToken.sol index 92d95677..3625c7fc 100644 --- a/contracts/index/TestIndexToken.sol +++ b/contracts/index/TestIndexToken.sol @@ -21,8 +21,8 @@ contract TestIndexToken is IndexToken { return _getDeployedValue(); } - function testGetPoolAssetValue() public view returns (uint256) { - return _getPoolAssetValue(); + function testGetVaultAssetValue() public view returns (uint256) { + return _getVaultAssetValue(); } function testGetAssetAmountAfterFees(uint256 amount, bool arbFee) From 11956f6594402151849d63c9484f58685eb9ac87 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Wed, 3 Aug 2022 13:26:18 -0400 Subject: [PATCH 09/16] Update tests --- test-integration/IndexToken.js | 66 +++++++-------- test-unit/IndexToken.js | 142 ++++++++++++++++----------------- 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/test-integration/IndexToken.js b/test-integration/IndexToken.js index 2efff807..630dba67 100644 --- a/test-integration/IndexToken.js +++ b/test-integration/IndexToken.js @@ -26,7 +26,7 @@ const vaultAssetAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; // use usdc agg for now const vaultAggAddress = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"; -describe.only("Contract: IndexToken", () => { +describe("Contract: IndexToken", () => { let deployer; let oracle; let adminSafe; @@ -238,8 +238,8 @@ describe.only("Contract: IndexToken", () => { }); }); - describe("Lock pool", () => { - it("Emergency Safe can lock and unlock pool", async () => { + describe("Lock vault", () => { + it("Emergency Safe can lock and unlock vault", async () => { await expect(indexToken.connect(emergencySafe).emergencyLock()).to.emit( indexToken, "Paused" @@ -262,7 +262,7 @@ describe.only("Contract: IndexToken", () => { ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); - it("Revert when calling deposit/redeem on locked pool", async () => { + it("Revert when calling deposit/redeem on locked vault", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -276,7 +276,7 @@ describe.only("Contract: IndexToken", () => { ).to.revertedWith("Pausable: paused"); }); - it("Revert when calling transferToLpAccount on locked pool", async () => { + it("Revert when calling transferToLpAccount on locked vault", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -310,7 +310,7 @@ describe.only("Contract: IndexToken", () => { ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); - it("Revert deposit when pool is locked", async () => { + it("Revert deposit when vault is locked", async () => { await indexToken.connect(emergencySafe).emergencyLockDeposit(); await expect( @@ -365,7 +365,7 @@ describe.only("Contract: IndexToken", () => { ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); - it("Revert redeem when pool is locked", async () => { + it("Revert redeem when vault is locked", async () => { await indexToken.connect(emergencySafe).emergencyLockRedeem(); await expect( @@ -403,19 +403,19 @@ describe.only("Contract: IndexToken", () => { it("Should transfer all deposited tokens to the emergencySafe", async () => { await indexToken.connect(randomUser).deposit(100000, receiver.address); - const prevPoolBalance = await asset.balanceOf(indexToken.address); + const prevVaultBalance = await asset.balanceOf(indexToken.address); const prevSafeBalance = await asset.balanceOf(emergencySafe.address); await indexToken.connect(emergencySafe).emergencyExit(asset.address); - const nextPoolBalance = await asset.balanceOf(indexToken.address); + const nextVaultBalance = await asset.balanceOf(indexToken.address); const nextSafeBalance = await asset.balanceOf(emergencySafe.address); - expect(nextPoolBalance).to.equal(0); - expect(nextSafeBalance.sub(prevSafeBalance)).to.equal(prevPoolBalance); + expect(nextVaultBalance).to.equal(0); + expect(nextSafeBalance.sub(prevSafeBalance)).to.equal(prevVaultBalance); }); - it("Should transfer tokens airdropped to the pool", async () => { + it("Should transfer tokens airdropped to the vault", async () => { const symbol = "AAVE"; const token = await ethers.getContractAt( "IDetailedERC20", @@ -430,16 +430,16 @@ describe.only("Contract: IndexToken", () => { deployer.address ); - const prevPoolBalance = await token.balanceOf(indexToken.address); + const prevVaultBalance = await token.balanceOf(indexToken.address); const prevSafeBalance = await token.balanceOf(emergencySafe.address); await indexToken.connect(emergencySafe).emergencyExit(token.address); - const nextPoolBalance = await token.balanceOf(indexToken.address); + const nextVaultBalance = await token.balanceOf(indexToken.address); const nextSafeBalance = await token.balanceOf(emergencySafe.address); - expect(nextPoolBalance).to.equal(0); - expect(nextSafeBalance.sub(prevSafeBalance)).to.equal(prevPoolBalance); + expect(nextVaultBalance).to.equal(0); + expect(nextSafeBalance.sub(prevSafeBalance)).to.equal(prevVaultBalance); }); it("Should emit the EmergencyExit event", async () => { @@ -475,7 +475,7 @@ describe.only("Contract: IndexToken", () => { beforeEach(async () => { /* these get rollbacked after each test due to snapshotting */ - // default to giving entire deployed value to the pool + // default to giving entire deployed value to the vault await updateTvlAgg(deployedValue); await oracleAdapter.connect(emergencySafe).emergencyUnlock(); }); @@ -509,9 +509,9 @@ describe.only("Contract: IndexToken", () => { assert(expectedAptMinted.gt(0)); }); - it("getPoolTotalValue returns value", async () => { - const val = await indexToken.getPoolTotalValue(); - console.debug(`\tPool Total Eth Value ${val.toString()}`); + it("getVaultTotalValue returns value", async () => { + const val = await indexToken.getVaultTotalValue(); + console.debug(`\tVault Total Eth Value ${val.toString()}`); assert(val.gt(0)); }); @@ -544,12 +544,12 @@ describe.only("Contract: IndexToken", () => { assert(assetAmount.gt(0)); }); - it("_getPoolAssetValue returns correct value", async () => { + it("_getVaultAssetValue returns correct value", async () => { let assetBalance = await asset.balanceOf(indexToken.address); let expectedAssetValue = await indexToken.getValueFromAssetAmount( assetBalance ); - expect(await indexToken.testGetPoolAssetValue()).to.equal( + expect(await indexToken.testGetVaultAssetValue()).to.equal( expectedAssetValue ); @@ -565,7 +565,7 @@ describe.only("Contract: IndexToken", () => { expectedAssetValue = await indexToken.getValueFromAssetAmount( assetBalance ); - expect(await indexToken.testGetPoolAssetValue()).to.equal( + expect(await indexToken.testGetVaultAssetValue()).to.equal( expectedAssetValue ); }); @@ -592,8 +592,8 @@ describe.only("Contract: IndexToken", () => { expect(topUpValue).to.be.gt(0); } - const poolAssetValue = await indexToken.testGetPoolAssetValue(); - // assuming we unwind the top-up value from the pool's deployed + const vaultAssetValue = await indexToken.testGetVaultAssetValue(); + // assuming we unwind the top-up value from the vault's deployed // capital, the reserve percentage of resulting deployed value // is what we are targeting const reservePercentage = await indexToken.reservePercentage(); @@ -603,7 +603,7 @@ describe.only("Contract: IndexToken", () => { .div(100); const tolerance = Math.ceil((await asset.decimals()) / 4); const allowedDeviation = tokenAmountToBigNumber(5, tolerance); - expect(poolAssetValue.add(topUpValue).sub(targetValue)).to.be.lt( + expect(vaultAssetValue.add(topUpValue).sub(targetValue)).to.be.lt( allowedDeviation ); }); @@ -771,7 +771,7 @@ describe.only("Contract: IndexToken", () => { const aptSupply = tokenAmountToBigNumber("100000"); await indexToken.testMint(deployer.address, aptSupply); - // seed the pool with asset + // seed the vault with asset const reserveBalance = tokenAmountToBigNumber("150000", decimals); await asset .connect(randomUser) @@ -805,8 +805,8 @@ describe.only("Contract: IndexToken", () => { const aptSupply = tokenAmountToBigNumber("10000"); await indexToken.testMint(deployer.address, aptSupply); - /* Setup pool and user APT amounts: - 1. give pool an asset reserve balance + /* Setup vault and user APT amounts: + 1. give vault an asset reserve balance 2. calculate the reserve's APT amount 3. transfer APT amount less than that to the user */ @@ -920,7 +920,7 @@ describe.only("Contract: IndexToken", () => { it("Revert when asset amount is greater than reserve", async () => { const decimals = await asset.decimals(); - // seed the pool with asset + // seed the vault with asset const reserveBalance = tokenAmountToBigNumber("150000", decimals); await asset .connect(randomUser) @@ -942,8 +942,8 @@ describe.only("Contract: IndexToken", () => { const indexSupply = tokenAmountToBigNumber("10000"); await indexToken.testMint(deployer.address, indexSupply); - /* Setup pool and user share amounts: - 1. give pool an asset reserve balance + /* Setup vault and user share amounts: + 1. give vault an asset reserve balance 2. calculate the reserve's share amount 3. transfer share amount less than that to the user */ @@ -1030,7 +1030,7 @@ describe.only("Contract: IndexToken", () => { deployer.address, tokenAmountToBigNumber("100000") ); - // seed pool with stablecoin + // seed vault with stablecoin await acquireToken( WHALE_POOLS[vaultAssetSymbol], indexToken.address, diff --git a/test-unit/IndexToken.js b/test-unit/IndexToken.js index 77fe1c8f..39a5c467 100644 --- a/test-unit/IndexToken.js +++ b/test-unit/IndexToken.js @@ -17,7 +17,7 @@ const IDetailedERC20 = artifacts.require("IDetailedERC20"); const AddressRegistry = artifacts.require("IAddressRegistryV2"); const OracleAdapter = artifacts.require("OracleAdapter"); -describe("Contract: IndexToken", () => { +describe.only("Contract: IndexToken", () => { // signers let deployer; let adminSafe; @@ -34,7 +34,7 @@ describe("Contract: IndexToken", () => { let addressRegistryMock; let oracleAdapterMock; - // pool + // vault let proxyAdmin; let indexToken; let logic; @@ -249,8 +249,8 @@ describe("Contract: IndexToken", () => { }); }); - describe("Lock pool", () => { - it("Emergency Safe can lock and unlock pool", async () => { + describe("Lock vault", () => { + it("Emergency Safe can lock and unlock vault", async () => { await expect(indexToken.connect(emergencySafe).emergencyLock()).to.emit( indexToken, "Paused" @@ -273,7 +273,7 @@ describe("Contract: IndexToken", () => { ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); - it("Revert when calling deposit on locked pool", async () => { + it("Revert when calling deposit on locked vault", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -281,7 +281,7 @@ describe("Contract: IndexToken", () => { ).to.revertedWith("Pausable: paused"); }); - it("Revert when calling mint on locked pool", async () => { + it("Revert when calling mint on locked vault", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -289,7 +289,7 @@ describe("Contract: IndexToken", () => { ).to.revertedWith("Pausable: paused"); }); - it("Revert when calling redeem on locked pool", async () => { + it("Revert when calling redeem on locked vault", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -299,7 +299,7 @@ describe("Contract: IndexToken", () => { ).to.revertedWith("Pausable: paused"); }); - it("Revert when calling withdraw on locked pool", async () => { + it("Revert when calling withdraw on locked vault", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -309,7 +309,7 @@ describe("Contract: IndexToken", () => { ).to.revertedWith("Pausable: paused"); }); - it("Revert when calling transferToLpAccount on locked pool from LP Account Funder", async () => { + it("Revert when calling transferToLpAccount on locked vault from LP Account Funder", async () => { await indexToken.connect(emergencySafe).emergencyLock(); await expect( @@ -402,7 +402,7 @@ describe("Contract: IndexToken", () => { }); }); - describe("_getPoolAssetValue", () => { + describe("_getVaultAssetValue", () => { it("Returns correct value regardless of deployed value", async () => { const decimals = 1; await assetMock.mock.decimals.returns(decimals); @@ -418,12 +418,12 @@ describe("Contract: IndexToken", () => { // force zero deployed value await oracleAdapterMock.mock.getTvl.returns(0); expect(await indexToken.testGetDeployedValue()).to.equal(0); - expect(await indexToken.testGetPoolAssetValue()).to.equal(expectedValue); + expect(await indexToken.testGetVaultAssetValue()).to.equal(expectedValue); // force non-zero deployed value await oracleAdapterMock.mock.getTvl.returns(1234); expect(await indexToken.testGetDeployedValue()).to.be.gt(0); - expect(await indexToken.testGetPoolAssetValue()).to.equal(expectedValue); + expect(await indexToken.testGetVaultAssetValue()).to.equal(expectedValue); }); }); @@ -445,7 +445,7 @@ describe("Contract: IndexToken", () => { }); }); - describe("getPoolTotalValue", () => { + describe("getVaultTotalValue", () => { it("Returns correct value", async () => { const decimals = 1; await assetMock.mock.decimals.returns(decimals); @@ -461,7 +461,7 @@ describe("Contract: IndexToken", () => { // asset ETH value: 75 * 2 / 10^1 = 15 const assetValue = assetBalance.mul(price).div(10 ** decimals); const expectedValue = assetValue.add(deployedValue); - expect(await indexToken.getPoolTotalValue()).to.equal(expectedValue); + expect(await indexToken.getVaultTotalValue()).to.equal(expectedValue); }); }); @@ -491,22 +491,22 @@ describe("Contract: IndexToken", () => { // zero deployed value await oracleAdapterMock.mock.getTvl.returns(0); - let poolTotalValue = await indexToken.getPoolTotalValue(); - let expectedValue = poolTotalValue.mul(aptAmount).div(aptSupply); + let vaultTotalValue = await indexToken.getVaultTotalValue(); + let expectedValue = vaultTotalValue.mul(aptAmount).div(aptSupply); expect(await indexToken.getUsdValue(aptAmount)).to.equal(expectedValue); // non-zero deployed value const deployedValue = tokenAmountToBigNumber(1234); await oracleAdapterMock.mock.getTvl.returns(deployedValue); - poolTotalValue = await indexToken.getPoolTotalValue(); - expectedValue = poolTotalValue.mul(aptAmount).div(aptSupply); + vaultTotalValue = await indexToken.getVaultTotalValue(); + expectedValue = vaultTotalValue.mul(aptAmount).div(aptSupply); expect(await indexToken.getUsdValue(aptAmount)).to.equal(expectedValue); }); }); describe("getReserveTopUpValue", () => { - it("Returns 0 when pool has zero total value", async () => { - // set pool total ETH value to 0 + it("Returns 0 when vault has zero total value", async () => { + // set vault total ETH value to 0 await oracleAdapterMock.mock.getAssetPrice.returns(1); await oracleAdapterMock.mock.getTvl.returns(0); await assetMock.mock.balanceOf.returns(0); @@ -518,12 +518,12 @@ describe("Contract: IndexToken", () => { it("Returns correctly calculated value when zero deployed value", async () => { await oracleAdapterMock.mock.getAssetPrice.returns(1); await oracleAdapterMock.mock.getTvl.returns(0); - // set positive pool asset ETH value, + // set positive vault asset ETH value, // which should result in negative reserve top-up const decimals = 6; await assetMock.mock.decimals.returns(decimals); - const poolBalance = tokenAmountToBigNumber(105e10, decimals); - await assetMock.mock.balanceOf.returns(poolBalance); + const vaultBalance = tokenAmountToBigNumber(105e10, decimals); + await assetMock.mock.balanceOf.returns(vaultBalance); const aptSupply = tokenAmountToBigNumber(10000); await indexToken.testMint(deployer.address, aptSupply); @@ -536,7 +536,7 @@ describe("Contract: IndexToken", () => { // is what we are targeting const reservePercentage = await indexToken.reservePercentage(); const targetValue = topUpAmount.mul(-1).mul(reservePercentage).div(100); - expect(poolBalance.add(topUpAmount)).to.equal(targetValue); + expect(vaultBalance.add(topUpAmount)).to.equal(targetValue); }); it("Returns reservePercentage of post deployed value when zero balance", async () => { @@ -555,7 +555,7 @@ describe("Contract: IndexToken", () => { const topUpAmount = await indexToken.getReserveTopUpValue(); const topUpValue = topUpAmount.mul(price).div(10 ** decimals); - // assuming we unwind the top-up value from the pool's deployed + // assuming we unwind the top-up value from the vault's deployed // capital, the reserve percentage of resulting deployed value // is what we are targetting const reservePercentage = await indexToken.reservePercentage(); @@ -570,8 +570,8 @@ describe("Contract: IndexToken", () => { const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); const decimals = 6; - const poolBalance = tokenAmountToBigNumber(1e10, decimals); - await assetMock.mock.balanceOf.returns(poolBalance); + const vaultBalance = tokenAmountToBigNumber(1e10, decimals); + await assetMock.mock.balanceOf.returns(vaultBalance); await assetMock.mock.decimals.returns(decimals); const aptSupply = tokenAmountToBigNumber(10000); @@ -580,13 +580,13 @@ describe("Contract: IndexToken", () => { const deployedValue = tokenAmountToBigNumber(500); await oracleAdapterMock.mock.getTvl.returns(deployedValue); - const poolAssetValue = await indexToken.testGetPoolAssetValue(); + const vaultAssetValue = await indexToken.testGetVaultAssetValue(); const topUpAmount = await indexToken.getReserveTopUpValue(); expect(topUpAmount).to.be.gt(0); const topUpValue = topUpAmount.mul(price).div(10 ** decimals); - // assuming we unwind the top-up value from the pool's deployed + // assuming we unwind the top-up value from the vault's deployed // capital, the reserve percentage of resulting deployed value // is what we are targeting const reservePercentage = await indexToken.reservePercentage(); @@ -594,15 +594,15 @@ describe("Contract: IndexToken", () => { .sub(topUpValue) .mul(reservePercentage) .div(100); - expect(poolAssetValue.add(topUpValue)).to.equal(targetValue); + expect(vaultAssetValue.add(topUpValue)).to.equal(targetValue); }); it("Returns correctly calculated value when top-up is negative", async () => { const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); const decimals = 6; - const poolBalance = tokenAmountToBigNumber(2.05e18, decimals); - await assetMock.mock.balanceOf.returns(poolBalance); + const vaultBalance = tokenAmountToBigNumber(2.05e18, decimals); + await assetMock.mock.balanceOf.returns(vaultBalance); await assetMock.mock.decimals.returns(decimals); const aptSupply = tokenAmountToBigNumber(10000); @@ -611,13 +611,13 @@ describe("Contract: IndexToken", () => { const deployedValue = tokenAmountToBigNumber(20); await oracleAdapterMock.mock.getTvl.returns(deployedValue); - const poolAssetValue = await indexToken.testGetPoolAssetValue(); + const vaultAssetValue = await indexToken.testGetVaultAssetValue(); const topUpAmount = await indexToken.getReserveTopUpValue(); expect(topUpAmount).to.be.lt(0); const topUpValue = topUpAmount.mul(price).div(10 ** decimals); - // assuming we deploy the top-up (abs) value to the pool's deployed + // assuming we deploy the top-up (abs) value to the vault's deployed // capital, the reserve percentage of resulting deployed value // is what we are targeting const reservePercentage = await indexToken.reservePercentage(); @@ -625,7 +625,7 @@ describe("Contract: IndexToken", () => { .sub(topUpValue) .mul(reservePercentage) .div(100); - expect(poolAssetValue.add(topUpValue)).to.equal(targetValue); + expect(vaultAssetValue.add(topUpValue)).to.equal(targetValue); }); }); @@ -651,13 +651,13 @@ describe("Contract: IndexToken", () => { expectedShareAmount ); - // result doesn't depend on pool's asset balance + // result doesn't depend on vault's asset balance await assetMock.mock.balanceOf.withArgs(indexToken.address).returns(0); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedShareAmount ); - // result doesn't depend on pool's deployed value + // result doesn't depend on vault's deployed value await oracleAdapterMock.mock.getTvl.returns(10000000); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedShareAmount @@ -669,16 +669,16 @@ describe("Contract: IndexToken", () => { const aptTotalSupply = tokenAmountToBigNumber("900", "18"); const depositAmount = tokenAmountToBigNumber("1000", decimals); - const poolBalance = tokenAmountToBigNumber("9999", decimals); + const vaultBalance = tokenAmountToBigNumber("9999", decimals); await oracleAdapterMock.mock.getAssetPrice.returns(1); - await assetMock.mock.balanceOf.returns(poolBalance); + await assetMock.mock.balanceOf.returns(vaultBalance); await assetMock.mock.decimals.returns(decimals); await indexToken.testMint(indexToken.address, aptTotalSupply); const expectedMintAmount = aptTotalSupply .mul(depositAmount) - .div(poolBalance); + .div(vaultBalance); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedMintAmount ); @@ -689,11 +689,11 @@ describe("Contract: IndexToken", () => { const aptTotalSupply = tokenAmountToBigNumber("900", "18"); const depositAmount = tokenAmountToBigNumber("1000", decimals); - const poolAssetBalance = tokenAmountToBigNumber("9999", decimals); + const vaultAssetBalance = tokenAmountToBigNumber("9999", decimals); const price = 1; await oracleAdapterMock.mock.getAssetPrice.returns(price); - await assetMock.mock.balanceOf.returns(poolAssetBalance); + await assetMock.mock.balanceOf.returns(vaultAssetBalance); await assetMock.mock.decimals.returns(decimals); await oracleAdapterMock.mock.getTvl.returns( @@ -703,10 +703,10 @@ describe("Contract: IndexToken", () => { await indexToken.testMint(indexToken.address, aptTotalSupply); const depositValue = depositAmount.mul(price).div(10 ** decimals); - const poolTotalValue = await indexToken.getPoolTotalValue(); + const vaultTotalValue = await indexToken.getVaultTotalValue(); const expectedMintAmount = aptTotalSupply .mul(depositValue) - .div(poolTotalValue); + .div(vaultTotalValue); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedMintAmount ); @@ -965,7 +965,7 @@ describe("Contract: IndexToken", () => { /* Test with range of deployed TVL values. Using 0 as deployed value forces old code paths without mAPT since - the pool's total ETH value comes purely from its asset + the vault's total ETH value comes purely from its asset holdings. */ const deployedValues = [ @@ -977,7 +977,7 @@ describe("Contract: IndexToken", () => { describe(` deployed value: ${deployedValue}`, () => { const decimals = 6; const depositAmount = tokenAmountToBigNumber(1, decimals); - const poolBalance = tokenAmountToBigNumber(1000, decimals); + const vaultBalance = tokenAmountToBigNumber(1000, decimals); // use EVM snapshots for test isolation let snapshotId; @@ -995,7 +995,7 @@ describe("Contract: IndexToken", () => { await assetMock.mock.allowance.returns(depositAmount); await assetMock.mock.balanceOf .withArgs(indexToken.address) - .returns(poolBalance); + .returns(vaultBalance); await assetMock.mock.transferFrom.returns(true); }); @@ -1020,11 +1020,11 @@ describe("Contract: IndexToken", () => { depositAmount ); - // mock the asset transfer to the pool, so we can - // check deposit event has the post-deposit pool ETH value + // mock the asset transfer to the vault, so we can + // check deposit event has the post-deposit vault ETH value await assetMock.mock.balanceOf .withArgs(indexToken.address) - .returns(poolBalance.add(depositAmount)); + .returns(vaultBalance.add(depositAmount)); const depositPromise = indexToken .connect(randomUser) @@ -1050,7 +1050,7 @@ describe("Contract: IndexToken", () => { * * expect("transferFrom") * .to.be.calledOnContract(assetMock) - * .withArgs(randomUser.address, poolToken.address, depositAmount); + * .withArgs(randomUser.address, vaultToken.address, depositAmount); * * Instead, we have to do some hacky revert-check logic. */ @@ -1108,7 +1108,7 @@ describe("Contract: IndexToken", () => { ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); - it("Revert deposit when pool is locked", async () => { + it("Revert deposit when vault is locked", async () => { await indexToken.connect(emergencySafe).emergencyLockDeposit(); await expect( @@ -1177,7 +1177,7 @@ describe("Contract: IndexToken", () => { /* Test with range of deployed TVL values. Using 0 as deployed value forces old code paths without mAPT since - the pool's total ETH value comes purely from its asset + the vault's total ETH value comes purely from its asset holdings. */ const deployedValues = [ @@ -1190,7 +1190,7 @@ describe("Contract: IndexToken", () => { const decimals = 6; const mintAmount = tokenAmountToBigNumber(1); let depositAmount; - const poolBalance = tokenAmountToBigNumber(1000, decimals); + const vaultBalance = tokenAmountToBigNumber(1000, decimals); // use EVM snapshots for test isolation let snapshotId; @@ -1207,7 +1207,7 @@ describe("Contract: IndexToken", () => { await assetMock.mock.decimals.returns(decimals); await assetMock.mock.balanceOf .withArgs(indexToken.address) - .returns(poolBalance); + .returns(vaultBalance); await assetMock.mock.transferFrom.returns(true); depositAmount = await indexToken.previewMint(mintAmount); @@ -1249,7 +1249,7 @@ describe("Contract: IndexToken", () => { * * expect("transferFrom") * .to.be.calledOnContract(assetMock) - * .withArgs(randomUser.address, poolToken.address, depositAmount); + * .withArgs(randomUser.address, indexToken.address, depositAmount); * * Instead, we have to do some hacky revert-check logic. */ @@ -1300,7 +1300,7 @@ describe("Contract: IndexToken", () => { /* Test with range of deployed TVL values. Using 0 as deployed value forces old code paths without mAPT since - the pool's total ETH value comes purely from its asset + the vault's total ETH value comes purely from its asset holdings. */ const deployedValues = [ @@ -1311,7 +1311,7 @@ describe("Contract: IndexToken", () => { deployedValues.forEach(function (deployedValue) { describe(` deployed value: ${deployedValue}`, () => { const decimals = 6; - const poolBalance = tokenAmountToBigNumber(1000, decimals); + const vaultBalance = tokenAmountToBigNumber(1000, decimals); const aptSupply = tokenAmountToBigNumber(1000000); let reserveAptAmount; let aptAmount; @@ -1329,15 +1329,15 @@ describe("Contract: IndexToken", () => { await oracleAdapterMock.mock.getAssetPrice.returns(price); await assetMock.mock.decimals.returns(decimals); - await assetMock.mock.allowance.returns(poolBalance); + await assetMock.mock.allowance.returns(vaultBalance); await assetMock.mock.balanceOf .withArgs(indexToken.address) - .returns(poolBalance); + .returns(vaultBalance); await assetMock.mock.transfer.returns(true); - // Mint APT supply to go along with pool's total ETH value. + // Mint APT supply to go along with vault's total ETH value. await indexToken.testMint(deployer.address, aptSupply); - reserveAptAmount = await indexToken.convertToShares(poolBalance); + reserveAptAmount = await indexToken.convertToShares(vaultBalance); await indexToken .connect(deployer) .transfer(randomUser.address, reserveAptAmount); @@ -1492,7 +1492,7 @@ describe("Contract: IndexToken", () => { ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); - it("Revert redeem when pool is locked", async () => { + it("Revert redeem when vault is locked", async () => { await indexToken.connect(emergencySafe).emergencyLockRedeem(); await expect( @@ -1514,7 +1514,7 @@ describe("Contract: IndexToken", () => { /* Test with range of deployed TVL values. Using 0 as deployed value forces old code paths without mAPT since - the pool's total ETH value comes purely from its asset + the vault's total ETH value comes purely from its asset holdings. */ const deployedValues = [ @@ -1525,7 +1525,7 @@ describe("Contract: IndexToken", () => { deployedValues.forEach(function (deployedValue) { describe(` deployed value: ${deployedValue}`, () => { const decimals = 6; - const poolBalance = tokenAmountToBigNumber(1000, decimals); + const vaultBalance = tokenAmountToBigNumber(1000, decimals); const aptSupply = tokenAmountToBigNumber(1000000); let reserveAptAmount; let aptAmount; @@ -1544,15 +1544,15 @@ describe("Contract: IndexToken", () => { await oracleAdapterMock.mock.getAssetPrice.returns(price); await assetMock.mock.decimals.returns(decimals); - await assetMock.mock.allowance.returns(poolBalance); + await assetMock.mock.allowance.returns(vaultBalance); await assetMock.mock.balanceOf .withArgs(indexToken.address) - .returns(poolBalance); + .returns(vaultBalance); await assetMock.mock.transfer.returns(true); - // Mint APT supply to go along with pool's total ETH value. + // Mint APT supply to go along with vault's total ETH value. await indexToken.testMint(deployer.address, aptSupply); - reserveAptAmount = await indexToken.convertToShares(poolBalance); + reserveAptAmount = await indexToken.convertToShares(vaultBalance); await indexToken .connect(deployer) .transfer(randomUser.address, reserveAptAmount); @@ -1688,7 +1688,7 @@ describe("Contract: IndexToken", () => { indexToken .connect(randomUser) .withdraw( - poolBalance.add(1), + vaultBalance.add(1), receiver.address, randomUser.address ) @@ -1698,7 +1698,7 @@ describe("Contract: IndexToken", () => { }); describe("Locking", () => { - it("Revert withdraw when pool is locked", async () => { + it("Revert withdraw when vault is locked", async () => { await indexToken.connect(emergencySafe).emergencyLockRedeem(); await expect( From e2ef2b84e505bd4dbdc8b01f9587b039ca6b9e18 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Wed, 3 Aug 2022 14:12:10 -0400 Subject: [PATCH 10/16] Fix unit tests from earlier change Having `_getDeployedValue` return 0 when zero supply botches some of the calc unit tests, which used to mock out mAPT. --- test-unit/IndexToken.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test-unit/IndexToken.js b/test-unit/IndexToken.js index 39a5c467..e83b9a71 100644 --- a/test-unit/IndexToken.js +++ b/test-unit/IndexToken.js @@ -17,7 +17,7 @@ const IDetailedERC20 = artifacts.require("IDetailedERC20"); const AddressRegistry = artifacts.require("IAddressRegistryV2"); const OracleAdapter = artifacts.require("OracleAdapter"); -describe.only("Contract: IndexToken", () => { +describe("Contract: IndexToken", () => { // signers let deployer; let adminSafe; @@ -403,6 +403,11 @@ describe.only("Contract: IndexToken", () => { }); describe("_getVaultAssetValue", () => { + beforeEach(async () => { + // create non-zero totalSupply so calls pass to oracle adapter + await indexToken.testMint(deployer.address, 1); + }); + it("Returns correct value regardless of deployed value", async () => { const decimals = 1; await assetMock.mock.decimals.returns(decimals); @@ -428,6 +433,11 @@ describe.only("Contract: IndexToken", () => { }); describe("_getDeployedValue", () => { + beforeEach(async () => { + // create non-zero totalSupply so calls pass to oracle adapter + await indexToken.testMint(deployer.address, 1); + }); + it("Delegates properly to Oracle Adapter", async () => { await oracleAdapterMock.mock.getTvl.returns(0); expect(await indexToken.testGetDeployedValue()).to.equal(0); @@ -446,6 +456,11 @@ describe.only("Contract: IndexToken", () => { }); describe("getVaultTotalValue", () => { + beforeEach(async () => { + // create non-zero totalSupply so calls pass to oracle adapter + await indexToken.testMint(deployer.address, 1); + }); + it("Returns correct value", async () => { const decimals = 1; await assetMock.mock.decimals.returns(decimals); From 82e3c4d98ded75d188eb7e216f95654891a04896 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Tue, 9 Aug 2022 10:43:18 -0400 Subject: [PATCH 11/16] Use direct imports --- contracts/index/IndexToken.sol | 46 ++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index eac94e30..3806bd96 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -2,25 +2,39 @@ pragma solidity 0.6.11; pragma experimental ABIEncoderV2; -import {IDetailedERC20, IEmergencyExit} from "contracts/common/Imports.sol"; -import {SafeERC20} from "contracts/libraries/Imports.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { - Initializable, - ERC20UpgradeSafe, - ReentrancyGuardUpgradeSafe, - PausableUpgradeSafe, - AccessControlUpgradeSafe, - Address as AddressUpgradeSafe, - SafeMath as SafeMathUpgradeSafe, - SignedSafeMath as SignedSafeMathUpgradeSafe -} from "contracts/proxy/Imports.sol"; -import {IAddressRegistryV2} from "contracts/registry/Imports.sol"; + ERC20UpgradeSafe +} from "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol"; import { - AggregatorV3Interface, - IOracleAdapter -} from "contracts/oracle/Imports.sol"; + ReentrancyGuardUpgradeSafe +} from "@openzeppelin/contracts-ethereum-package/contracts/utils/ReentrancyGuard.sol"; +import { + Address as AddressUpgradeSafe +} from "@openzeppelin/contracts-ethereum-package/contracts/utils/Address.sol"; +import { + PausableUpgradeSafe +} from "@openzeppelin/contracts-ethereum-package/contracts/utils/Pausable.sol"; +import { + SafeMath as SafeMathUpgradeSafe +} from "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; +import { + SignedSafeMath as SignedSafeMathUpgradeSafe +} from "@openzeppelin/contracts-ethereum-package/contracts/math/SignedSafeMath.sol"; -import {IERC4626, IFeeVault, ILockingVault, IReserveVault} from "./Imports.sol"; +import { + AccessControlUpgradeSafe +} from "contracts/proxy/AccessControlUpgradeSafe.sol"; +import {IAddressRegistryV2} from "contracts/registry/IAddressRegistryV2.sol"; +import {IDetailedERC20} from "contracts/common/IDetailedERC20.sol"; +import {IEmergencyExit} from "contracts/common/IEmergencyExit.sol"; +import {Initializable} from "contracts/proxy/Initializable.sol"; +import {IOracleAdapter} from "contracts/oracle/IOracleAdapter.sol"; + +import {IERC4626} from "./IERC4626.sol"; +import {IFeeVault} from "./IFeeVault.sol"; +import {ILockingVault} from "./ILockingVault.sol"; +import {IReserveVault} from "./IReserveVault.sol"; /** * @notice Collect user deposits so they can be lent to the LP Account From 80d8867f440d087adabb10a09694d34bee8bcea5 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Tue, 9 Aug 2022 10:51:24 -0400 Subject: [PATCH 12/16] Remove mapt naming --- contracts/index/IndexToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index 3806bd96..9b9b236e 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -549,8 +549,8 @@ contract IndexToken is */ function getVaultTotalValue() public view returns (uint256) { uint256 assetValue = _getVaultAssetValue(); - uint256 mAptValue = _getDeployedValue(); - return assetValue.add(mAptValue); + uint256 deployedValue = _getDeployedValue(); + return assetValue.add(deployedValue); } function getValueFromAssetAmount(uint256 assetAmount) From 19e2039e9f758f8a6056d2a004f956475ce8ccf1 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Tue, 9 Aug 2022 14:31:31 -0400 Subject: [PATCH 13/16] Remove address registry dependency; use setters --- contracts/index/IndexToken.sol | 98 +++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index 9b9b236e..bdc6a201 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -66,11 +66,9 @@ contract IndexToken is /* ------------------------------- */ /* impl-specific storage variables */ /* ------------------------------- */ - /** - * @notice registry to fetch core platform addresses from - * @dev this slot replaces the last V1 slot for the price agg - */ - IAddressRegistryV2 public addressRegistry; + + address public oracleAdapter; + address public lpAccount; /** @notice true if depositing is locked */ bool public depositLock; @@ -98,8 +96,10 @@ contract IndexToken is /* ------------------------------- */ - /** @notice Log when the address registry is changed */ - event AddressRegistryChanged(address); + /** @notice Log when the Oracle Adapter is changed */ + event OracleAdapterChanged(address); + /** @notice Log when the LP Account is changed */ + event LpAccountChanged(address); /** * @dev Since the proxy delegate calls to this "logic" contract, any @@ -113,11 +113,18 @@ contract IndexToken is * repeatedly. It should be called during the deployment so that * it cannot be called by someone else later. */ - function initialize(address addressRegistry_, address asset_) - external - initializer - { - require(address(asset_) != address(0), "INVALID_TOKEN"); + function initialize( + address asset_, + address emergencySafe, + address adminSafe, + address oracleAdapter, + address lpAccount, + address lpAccountFunder + ) external initializer { + require(address(asset_) != address(0), "INVALID_ADDRESS"); + require(address(asset_) != address(0), "INVALID_ADDRESS"); + require(address(asset_) != address(0), "INVALID_ADDRESS"); + require(address(asset_) != address(0), "INVALID_ADDRESS"); // initialize ancestor storage __Context_init_unchained(); @@ -126,22 +133,19 @@ contract IndexToken is __Pausable_init_unchained(); __ERC20_init_unchained("Convex Index Token", "idxCVX"); + _setupRole(DEFAULT_ADMIN_ROLE, emergencySafe); + _setupRole(ADMIN_ROLE, adminSafe); + _setupRole(EMERGENCY_ROLE, emergencySafe); + _setupRole(CONTRACT_ROLE, lpAccountFunder); + // initialize impl-specific storage + _setOracleAdapter(oracleAdapter); + _setLpAccount(lpAccount); + depositLock = false; redeemLock = false; asset = asset_; - _setAddressRegistry(addressRegistry_); - - // FIXME: these need to be Cortex DAO addresses - _setupRole(DEFAULT_ADMIN_ROLE, addressRegistry.emergencySafeAddress()); - _setupRole(ADMIN_ROLE, addressRegistry.adminSafeAddress()); - _setupRole(EMERGENCY_ROLE, addressRegistry.emergencySafeAddress()); - _setupRole( - CONTRACT_ROLE, - addressRegistry.getAddress("lpAccountFunder") - ); - arbitrageFeePeriod = 1 days; arbitrageFee = 5; reservePercentage = 5; @@ -354,22 +358,27 @@ contract IndexToken is whenNotPaused onlyContractRole { - IDetailedERC20(asset).safeTransfer( - addressRegistry.lpAccountAddress(), - amount - ); + IDetailedERC20(asset).safeTransfer(lpAccount, amount); } /** - * @notice Set the new address registry - * @param addressRegistry_ The new address registry + * @notice Set the new oracle adapter + * @param oracleAdapter_ The new address */ - function emergencySetAddressRegistry(address addressRegistry_) + function emergencySetOracleAdapter(address oracleAdapter_) external nonReentrant onlyEmergencyRole { - _setAddressRegistry(addressRegistry_); + _setOracleAdapter(oracleAdapter_); + } + + function emergencySetLpAccount(address lpAccount_) + external + nonReentrant + onlyEmergencyRole + { + _setLpAccount(lpAccount_); } function setArbitrageFee(uint256 feePercentage, uint256 feePeriod) @@ -405,12 +414,11 @@ contract IndexToken is } function emergencyExit(address token) external override onlyEmergencyRole { - address emergencySafe = addressRegistry.emergencySafeAddress(); IDetailedERC20 token_ = IDetailedERC20(token); uint256 balance = token_.balanceOf(address(this)); - token_.safeTransfer(emergencySafe, balance); + token_.safeTransfer(msg.sender, balance); - emit EmergencyExit(emergencySafe, token_, balance); + emit EmergencyExit(msg.sender, token_, balance); } function getUsdValue(uint256 shareAmount) external view returns (uint256) { @@ -566,9 +574,7 @@ contract IndexToken is } function getAssetPrice() public view returns (uint256) { - IOracleAdapter oracleAdapter = - IOracleAdapter(addressRegistry.oracleAdapterAddress()); - return oracleAdapter.getAssetPrice(address(asset)); + return IOracleAdapter(oracleAdapter).getAssetPrice(address(asset)); } /** @@ -635,10 +641,16 @@ contract IndexToken is return totalValue.mul(10**decimals).div(assetPrice); } - function _setAddressRegistry(address addressRegistry_) internal { - require(addressRegistry_.isContract(), "INVALID_ADDRESS"); - addressRegistry = IAddressRegistryV2(addressRegistry_); - emit AddressRegistryChanged(addressRegistry_); + function _setOracleAdapter(address oracleAdapter_) internal { + require(oracleAdapter_.isContract(), "INVALID_ADDRESS"); + oracleAdapter = oracleAdapter_; + emit OracleAdapterChanged(oracleAdapter_); + } + + function _setLpAccount(address lpAccount_) internal { + require(lpAccount_.isContract(), "INVALID_ADDRESS"); + lpAccount = lpAccount_; + emit LpAccountChanged(lpAccount_); } /** @@ -712,9 +724,7 @@ contract IndexToken is function _getDeployedValue() internal view returns (uint256) { if (totalSupply() == 0) return 0; - IOracleAdapter oracleAdapter = - IOracleAdapter(addressRegistry.oracleAdapterAddress()); - return oracleAdapter.getTvl(); + return IOracleAdapter(oracleAdapter).getTvl(); } function _previewRedeem(uint256 shareAmount, bool arbFee) From 48f47d389532074f71b39de7c8e7942dcea67a13 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Wed, 10 Aug 2022 15:14:04 -0400 Subject: [PATCH 14/16] Validate contract addresses --- contracts/index/IndexToken.sol | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/contracts/index/IndexToken.sol b/contracts/index/IndexToken.sol index bdc6a201..83d229ee 100644 --- a/contracts/index/IndexToken.sol +++ b/contracts/index/IndexToken.sol @@ -115,16 +115,18 @@ contract IndexToken is */ function initialize( address asset_, - address emergencySafe, - address adminSafe, - address oracleAdapter, - address lpAccount, - address lpAccountFunder - ) external initializer { - require(address(asset_) != address(0), "INVALID_ADDRESS"); - require(address(asset_) != address(0), "INVALID_ADDRESS"); - require(address(asset_) != address(0), "INVALID_ADDRESS"); - require(address(asset_) != address(0), "INVALID_ADDRESS"); + address emergencySafe_, + address adminSafe_, + address oracleAdapter_, + address lpAccount_, + address lpAccountFunder_ + ) external { + require(asset_.isContract(), "INVALID_CONTRACT"); + require(emergencySafe_.isContract(), "INVALID_CONTRACT"); + require(adminSafe_.isContract(), "INVALID_CONTRACT"); + require(oracleAdapter_.isContract(), "INVALID_CONTRACT"); + require(lpAccount_.isContract(), "INVALID_CONTRACT"); + require(lpAccountFunder_.isContract(), "INVALID_CONTRACT"); // initialize ancestor storage __Context_init_unchained(); @@ -133,14 +135,14 @@ contract IndexToken is __Pausable_init_unchained(); __ERC20_init_unchained("Convex Index Token", "idxCVX"); - _setupRole(DEFAULT_ADMIN_ROLE, emergencySafe); - _setupRole(ADMIN_ROLE, adminSafe); - _setupRole(EMERGENCY_ROLE, emergencySafe); - _setupRole(CONTRACT_ROLE, lpAccountFunder); + _setupRole(DEFAULT_ADMIN_ROLE, emergencySafe_); + _setupRole(ADMIN_ROLE, adminSafe_); + _setupRole(EMERGENCY_ROLE, emergencySafe_); + _setupRole(CONTRACT_ROLE, lpAccountFunder_); // initialize impl-specific storage - _setOracleAdapter(oracleAdapter); - _setLpAccount(lpAccount); + _setOracleAdapter(oracleAdapter_); + _setLpAccount(lpAccount_); depositLock = false; redeemLock = false; @@ -642,13 +644,13 @@ contract IndexToken is } function _setOracleAdapter(address oracleAdapter_) internal { - require(oracleAdapter_.isContract(), "INVALID_ADDRESS"); + require(oracleAdapter_.isContract(), "INVALID_CONTRACT"); oracleAdapter = oracleAdapter_; emit OracleAdapterChanged(oracleAdapter_); } function _setLpAccount(address lpAccount_) internal { - require(lpAccount_.isContract(), "INVALID_ADDRESS"); + require(lpAccount_.isContract(), "INVALID_CONTRACT"); lpAccount = lpAccount_; emit LpAccountChanged(lpAccount_); } From 98a2ac4c2ca5c0e613fb14065193750741debaf5 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Wed, 10 Aug 2022 15:19:51 -0400 Subject: [PATCH 15/16] Update unit tests --- test-unit/IndexToken.js | 448 +++++++++++++++++++++------------------- 1 file changed, 235 insertions(+), 213 deletions(-) diff --git a/test-unit/IndexToken.js b/test-unit/IndexToken.js index e83b9a71..b2bc4d9d 100644 --- a/test-unit/IndexToken.js +++ b/test-unit/IndexToken.js @@ -10,29 +10,29 @@ const { ZERO_ADDRESS, FAKE_ADDRESS, tokenAmountToBigNumber, - bytes32, + impersonateAccount, } = require("../utils/helpers"); const IDetailedERC20 = artifacts.require("IDetailedERC20"); -const AddressRegistry = artifacts.require("IAddressRegistryV2"); const OracleAdapter = artifacts.require("OracleAdapter"); -describe("Contract: IndexToken", () => { +describe.only("Contract: IndexToken", () => { // signers let deployer; - let adminSafe; - let emergencySafe; - let lpAccountFunder; - let lpAccount; - let lpSafe; + let adminSafeSigner; + let emergencySafeSigner; + let lpAccountFunderSigner; let randomUser; let receiver; let anotherUser; // mocks - let assetMock; - let addressRegistryMock; - let oracleAdapterMock; + let asset; + let emergencySafe; + let adminSafe; + let oracleAdapter; + let lpAccount; + let lpAccountFunder; // vault let proxyAdmin; @@ -52,44 +52,18 @@ describe("Contract: IndexToken", () => { }); before(async () => { - [ - deployer, - lpAccount, - lpAccountFunder, - adminSafe, - emergencySafe, - lpSafe, - randomUser, - receiver, - anotherUser, - ] = await ethers.getSigners(); + [deployer, randomUser, receiver, anotherUser] = await ethers.getSigners(); const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin"); proxyAdmin = await ProxyAdmin.deploy(); await proxyAdmin.deployed(); - assetMock = await deployMockContract(deployer, IDetailedERC20.abi); - - addressRegistryMock = await deployMockContract( - deployer, - AddressRegistry.abi - ); - - await addressRegistryMock.mock.getAddress - .withArgs(bytes32("lpAccountFunder")) - .returns(lpAccountFunder.address); - - oracleAdapterMock = await deployMockContract(deployer, OracleAdapter.abi); - await addressRegistryMock.mock.oracleAdapterAddress.returns( - oracleAdapterMock.address - ); - - await addressRegistryMock.mock.lpAccountAddress.returns(lpAccount.address); - await addressRegistryMock.mock.lpSafeAddress.returns(lpSafe.address); - await addressRegistryMock.mock.adminSafeAddress.returns(adminSafe.address); - await addressRegistryMock.mock.emergencySafeAddress.returns( - emergencySafe.address - ); + asset = await deployMockContract(deployer, IDetailedERC20.abi); + emergencySafe = await deployMockContract(deployer, []); + adminSafe = await deployMockContract(deployer, []); + oracleAdapter = await deployMockContract(deployer, OracleAdapter.abi); + lpAccount = await deployMockContract(deployer, []); + lpAccountFunder = await deployMockContract(deployer, []); const IndexToken = await ethers.getContractFactory("TestIndexToken"); logic = await IndexToken.deploy(); @@ -99,8 +73,15 @@ describe("Contract: IndexToken", () => { "TransparentUpgradeableProxy" ); const initData = IndexToken.interface.encodeFunctionData( - "initialize(address,address)", - [addressRegistryMock.address, assetMock.address] + "initialize(address,address,address,address,address,address)", + [ + asset.address, + emergencySafe.address, + adminSafe.address, + oracleAdapter.address, + lpAccount.address, + lpAccountFunder.address, + ] ); const proxy = await TransparentUpgradeableProxy.deploy( logic.address, @@ -110,19 +91,31 @@ describe("Contract: IndexToken", () => { await proxy.deployed(); indexToken = await IndexToken.attach(proxy.address); + + emergencySafeSigner = await impersonateAccount(emergencySafe, 100); + adminSafeSigner = await impersonateAccount(adminSafe, 100); + lpAccountFunderSigner = await impersonateAccount(lpAccountFunder, 100); }); describe("Initialize", () => { - it("Revert when address registry address is non-contract", async () => { - await expect( - logic.initialize(FAKE_ADDRESS, assetMock.address) - ).to.be.revertedWith("INVALID_ADDRESS"); - }); - - it("Revert when token address is zero address", async () => { - await expect( - logic.initialize(addressRegistryMock.address, ZERO_ADDRESS) - ).to.be.revertedWith("INVALID_TOKEN"); + it("Revert when address is zero address", async () => { + const addresses = [ + asset.address, + emergencySafe.address, + adminSafe.address, + oracleAdapter.address, + lpAccount.address, + lpAccountFunder.address, + ]; + let temp; + for (let i = 0; i < addresses.length; i++) { + temp = addresses[i]; + addresses[i] = FAKE_ADDRESS; + await expect(logic.initialize(...addresses)).to.be.revertedWith( + "INVALID_CONTRACT" + ); + addresses[i] = temp; + } }); }); @@ -181,7 +174,7 @@ describe("Contract: IndexToken", () => { }); it("Asset is set correctly", async () => { - expect(await indexToken.asset()).to.equal(assetMock.address); + expect(await indexToken.asset()).to.equal(asset.address); }); it("deposit is unlocked", async () => { @@ -205,21 +198,21 @@ describe("Contract: IndexToken", () => { }); }); - describe("Set address registry", () => { + describe("Set Oracle Adapter", () => { it("Emergency Safe can set", async () => { const dummyContract = await deployMockContract(deployer, []); await indexToken - .connect(emergencySafe) - .emergencySetAddressRegistry(dummyContract.address); - assert.equal(await indexToken.addressRegistry(), dummyContract.address); + .connect(emergencySafeSigner) + .emergencySetOracleAdapter(dummyContract.address); + assert.equal(await indexToken.oracleAdapter(), dummyContract.address); }); it("Revert on non-contract address", async () => { await expect( indexToken - .connect(emergencySafe) - .emergencySetAddressRegistry(FAKE_ADDRESS) - ).to.be.revertedWith("INVALID_ADDRESS"); + .connect(emergencySafeSigner) + .emergencySetOracleAdapter(FAKE_ADDRESS) + ).to.be.revertedWith("INVALID_CONTRACT"); }); it("Revert when unpermissioned account attempts to set", async () => { @@ -227,7 +220,34 @@ describe("Contract: IndexToken", () => { await expect( indexToken .connect(randomUser) - .emergencySetAddressRegistry(dummyContract.address) + .emergencySetOracleAdapter(dummyContract.address) + ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); + }); + }); + + describe("Set Lp Account", () => { + it("Emergency Safe can set", async () => { + const dummyContract = await deployMockContract(deployer, []); + await indexToken + .connect(emergencySafeSigner) + .emergencySetLpAccount(dummyContract.address); + assert.equal(await indexToken.lpAccount(), dummyContract.address); + }); + + it("Revert on non-contract address", async () => { + await expect( + indexToken + .connect(emergencySafeSigner) + .emergencySetLpAccount(FAKE_ADDRESS) + ).to.be.revertedWith("INVALID_CONTRACT"); + }); + + it("Revert when unpermissioned account attempts to set", async () => { + const dummyContract = await deployMockContract(deployer, []); + await expect( + indexToken + .connect(randomUser) + .emergencySetLpAccount(dummyContract.address) ).to.be.revertedWith("NOT_EMERGENCY_ROLE"); }); }); @@ -235,12 +255,12 @@ describe("Contract: IndexToken", () => { describe("getAssetPrice", () => { it("Delegates to oracle adapter", async () => { const price = tokenAmountToBigNumber("1.02", 8); - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); expect(await indexToken.getAssetPrice()).to.equal(price); }); it("Reverts with same reason as oracle adapter", async () => { - await oracleAdapterMock.mock.getAssetPrice.revertsWithReason( + await oracleAdapter.mock.getAssetPrice.revertsWithReason( "SOMETHING_WRONG" ); await expect(indexToken.getAssetPrice()).to.be.revertedWith( @@ -251,14 +271,12 @@ describe("Contract: IndexToken", () => { describe("Lock vault", () => { it("Emergency Safe can lock and unlock vault", async () => { - await expect(indexToken.connect(emergencySafe).emergencyLock()).to.emit( - indexToken, - "Paused" - ); - await expect(indexToken.connect(emergencySafe).emergencyUnlock()).to.emit( - indexToken, - "Unpaused" - ); + await expect( + indexToken.connect(emergencySafeSigner).emergencyLock() + ).to.emit(indexToken, "Paused"); + await expect( + indexToken.connect(emergencySafeSigner).emergencyUnlock() + ).to.emit(indexToken, "Unpaused"); }); it("Revert when unpermissioned account attempts to lock", async () => { @@ -274,7 +292,7 @@ describe("Contract: IndexToken", () => { }); it("Revert when calling deposit on locked vault", async () => { - await indexToken.connect(emergencySafe).emergencyLock(); + await indexToken.connect(emergencySafeSigner).emergencyLock(); await expect( indexToken.connect(randomUser).deposit(50, randomUser.address) @@ -282,7 +300,7 @@ describe("Contract: IndexToken", () => { }); it("Revert when calling mint on locked vault", async () => { - await indexToken.connect(emergencySafe).emergencyLock(); + await indexToken.connect(emergencySafeSigner).emergencyLock(); await expect( indexToken.connect(randomUser).mint(50, randomUser.address) @@ -290,7 +308,7 @@ describe("Contract: IndexToken", () => { }); it("Revert when calling redeem on locked vault", async () => { - await indexToken.connect(emergencySafe).emergencyLock(); + await indexToken.connect(emergencySafeSigner).emergencyLock(); await expect( indexToken @@ -300,7 +318,7 @@ describe("Contract: IndexToken", () => { }); it("Revert when calling withdraw on locked vault", async () => { - await indexToken.connect(emergencySafe).emergencyLock(); + await indexToken.connect(emergencySafeSigner).emergencyLock(); await expect( indexToken @@ -310,22 +328,23 @@ describe("Contract: IndexToken", () => { }); it("Revert when calling transferToLpAccount on locked vault from LP Account Funder", async () => { - await indexToken.connect(emergencySafe).emergencyLock(); + await indexToken.connect(emergencySafeSigner).emergencyLock(); await expect( - indexToken.connect(lpAccountFunder).transferToLpAccount(100) + indexToken.connect(lpAccountFunderSigner).transferToLpAccount(100) ).to.revertedWith("Pausable: paused"); }); }); describe("Transfer to LP Account", () => { before(async () => { - await assetMock.mock.transfer.returns(true); + await asset.mock.transfer.returns(true); }); it("LP Account Funder can call transferToLpAccount", async () => { - await expect(indexToken.connect(lpAccountFunder).transferToLpAccount(100)) - .to.not.be.reverted; + await expect( + indexToken.connect(lpAccountFunderSigner).transferToLpAccount(100) + ).to.not.be.reverted; }); it("Revert when unpermissioned account calls transferToLpAccount", async () => { @@ -340,7 +359,7 @@ describe("Contract: IndexToken", () => { const newFeePeriod = 12 * 60 * 60; await expect( indexToken - .connect(adminSafe) + .connect(adminSafeSigner) .setArbitrageFee(newArbitrageFee, newFeePeriod) ).to.not.be.reverted; expect(await indexToken.arbitrageFee()).to.equal(newArbitrageFee); @@ -357,7 +376,7 @@ describe("Contract: IndexToken", () => { it("Admin Safe can set", async () => { const newPercentage = 10; await expect( - indexToken.connect(adminSafe).setReservePercentage(newPercentage) + indexToken.connect(adminSafeSigner).setReservePercentage(newPercentage) ).to.not.be.reverted; expect(await indexToken.reservePercentage()).to.equal(newPercentage); }); @@ -371,8 +390,9 @@ describe("Contract: IndexToken", () => { describe("Set withdrawFee", () => { it("Admin Safe can set", async () => { const newWithdrawFee = 1200; - await expect(indexToken.connect(adminSafe).setWithdrawFee(newWithdrawFee)) - .to.not.be.reverted; + await expect( + indexToken.connect(adminSafeSigner).setWithdrawFee(newWithdrawFee) + ).to.not.be.reverted; expect(await indexToken.withdrawFee()).to.equal(newWithdrawFee); }); @@ -389,9 +409,9 @@ describe("Contract: IndexToken", () => { it("Returns correct value", async () => { const decimals = 1; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const price = 2; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); const assetAmount = tokenAmountToBigNumber(5, decimals); // 50 * 2 / 10 ^ 1 @@ -410,23 +430,23 @@ describe("Contract: IndexToken", () => { it("Returns correct value regardless of deployed value", async () => { const decimals = 1; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const balance = tokenAmountToBigNumber("7.5", decimals); - await assetMock.mock.balanceOf.returns(balance); + await asset.mock.balanceOf.returns(balance); const price = 2; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); // 75 * 2 / 10^1 const expectedValue = balance.mul(price).div(10 ** decimals); // force zero deployed value - await oracleAdapterMock.mock.getTvl.returns(0); + await oracleAdapter.mock.getTvl.returns(0); expect(await indexToken.testGetDeployedValue()).to.equal(0); expect(await indexToken.testGetVaultAssetValue()).to.equal(expectedValue); // force non-zero deployed value - await oracleAdapterMock.mock.getTvl.returns(1234); + await oracleAdapter.mock.getTvl.returns(1234); expect(await indexToken.testGetDeployedValue()).to.be.gt(0); expect(await indexToken.testGetVaultAssetValue()).to.equal(expectedValue); }); @@ -439,16 +459,16 @@ describe("Contract: IndexToken", () => { }); it("Delegates properly to Oracle Adapter", async () => { - await oracleAdapterMock.mock.getTvl.returns(0); + await oracleAdapter.mock.getTvl.returns(0); expect(await indexToken.testGetDeployedValue()).to.equal(0); const deployedValue = tokenAmountToBigNumber(12345); - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); expect(await indexToken.testGetDeployedValue()).to.equal(deployedValue); }); it("Reverts with same reason when mAPT reverts", async () => { - await oracleAdapterMock.mock.getTvl.revertsWithReason("SOMETHING_WRONG"); + await oracleAdapter.mock.getTvl.revertsWithReason("SOMETHING_WRONG"); await expect(indexToken.testGetDeployedValue()).to.be.revertedWith( "SOMETHING_WRONG" ); @@ -463,15 +483,15 @@ describe("Contract: IndexToken", () => { it("Returns correct value", async () => { const decimals = 1; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const assetBalance = tokenAmountToBigNumber("7.5", decimals); - await assetMock.mock.balanceOf.returns(assetBalance); + await asset.mock.balanceOf.returns(assetBalance); const deployedValue = tokenAmountToBigNumber(1234); - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const price = 2; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); // asset ETH value: 75 * 2 / 10^1 = 15 const assetValue = assetBalance.mul(price).div(10 ** decimals); @@ -495,24 +515,24 @@ describe("Contract: IndexToken", () => { it("Returns correct value", async () => { await indexToken.testMint(randomUser.address, 100); - await assetMock.mock.decimals.returns(0); - await assetMock.mock.balanceOf.returns(100); + await asset.mock.decimals.returns(0); + await asset.mock.balanceOf.returns(100); const price = 2; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); const aptSupply = await indexToken.totalSupply(); const aptAmount = tokenAmountToBigNumber(10); // zero deployed value - await oracleAdapterMock.mock.getTvl.returns(0); + await oracleAdapter.mock.getTvl.returns(0); let vaultTotalValue = await indexToken.getVaultTotalValue(); let expectedValue = vaultTotalValue.mul(aptAmount).div(aptSupply); expect(await indexToken.getUsdValue(aptAmount)).to.equal(expectedValue); // non-zero deployed value const deployedValue = tokenAmountToBigNumber(1234); - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); vaultTotalValue = await indexToken.getVaultTotalValue(); expectedValue = vaultTotalValue.mul(aptAmount).div(aptSupply); expect(await indexToken.getUsdValue(aptAmount)).to.equal(expectedValue); @@ -522,23 +542,23 @@ describe("Contract: IndexToken", () => { describe("getReserveTopUpValue", () => { it("Returns 0 when vault has zero total value", async () => { // set vault total ETH value to 0 - await oracleAdapterMock.mock.getAssetPrice.returns(1); - await oracleAdapterMock.mock.getTvl.returns(0); - await assetMock.mock.balanceOf.returns(0); - await assetMock.mock.decimals.returns(6); + await oracleAdapter.mock.getAssetPrice.returns(1); + await oracleAdapter.mock.getTvl.returns(0); + await asset.mock.balanceOf.returns(0); + await asset.mock.decimals.returns(6); expect(await indexToken.getReserveTopUpValue()).to.equal(0); }); it("Returns correctly calculated value when zero deployed value", async () => { - await oracleAdapterMock.mock.getAssetPrice.returns(1); - await oracleAdapterMock.mock.getTvl.returns(0); + await oracleAdapter.mock.getAssetPrice.returns(1); + await oracleAdapter.mock.getTvl.returns(0); // set positive vault asset ETH value, // which should result in negative reserve top-up const decimals = 6; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const vaultBalance = tokenAmountToBigNumber(105e10, decimals); - await assetMock.mock.balanceOf.returns(vaultBalance); + await asset.mock.balanceOf.returns(vaultBalance); const aptSupply = tokenAmountToBigNumber(10000); await indexToken.testMint(deployer.address, aptSupply); @@ -556,16 +576,16 @@ describe("Contract: IndexToken", () => { it("Returns reservePercentage of post deployed value when zero balance", async () => { const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); - await assetMock.mock.balanceOf.returns(0); + await oracleAdapter.mock.getAssetPrice.returns(price); + await asset.mock.balanceOf.returns(0); const decimals = 6; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const aptSupply = tokenAmountToBigNumber(10000); await indexToken.testMint(deployer.address, aptSupply); const deployedValue = tokenAmountToBigNumber(1000); - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const topUpAmount = await indexToken.getReserveTopUpValue(); const topUpValue = topUpAmount.mul(price).div(10 ** decimals); @@ -583,17 +603,17 @@ describe("Contract: IndexToken", () => { it("Returns correctly calculated value when top-up is positive", async () => { const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); const decimals = 6; const vaultBalance = tokenAmountToBigNumber(1e10, decimals); - await assetMock.mock.balanceOf.returns(vaultBalance); - await assetMock.mock.decimals.returns(decimals); + await asset.mock.balanceOf.returns(vaultBalance); + await asset.mock.decimals.returns(decimals); const aptSupply = tokenAmountToBigNumber(10000); await indexToken.testMint(deployer.address, aptSupply); const deployedValue = tokenAmountToBigNumber(500); - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const vaultAssetValue = await indexToken.testGetVaultAssetValue(); const topUpAmount = await indexToken.getReserveTopUpValue(); @@ -614,17 +634,17 @@ describe("Contract: IndexToken", () => { it("Returns correctly calculated value when top-up is negative", async () => { const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); const decimals = 6; const vaultBalance = tokenAmountToBigNumber(2.05e18, decimals); - await assetMock.mock.balanceOf.returns(vaultBalance); - await assetMock.mock.decimals.returns(decimals); + await asset.mock.balanceOf.returns(vaultBalance); + await asset.mock.decimals.returns(decimals); const aptSupply = tokenAmountToBigNumber(10000); await indexToken.testMint(deployer.address, aptSupply); const deployedValue = tokenAmountToBigNumber(20); - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const vaultAssetValue = await indexToken.testGetVaultAssetValue(); const topUpAmount = await indexToken.getReserveTopUpValue(); @@ -646,34 +666,34 @@ describe("Contract: IndexToken", () => { describe("convertToShares", () => { beforeEach(async () => { - await oracleAdapterMock.mock.getTvl.returns(0); + await oracleAdapter.mock.getTvl.returns(0); }); it("Uses 1:1 token ratio with zero total supply", async () => { expect(await indexToken.totalSupply()).to.equal(0); const decimals = 6; - await assetMock.mock.decimals.returns(decimals); - await oracleAdapterMock.mock.getAssetPrice.returns(1); + await asset.mock.decimals.returns(decimals); + await oracleAdapter.mock.getAssetPrice.returns(1); const depositAmount = tokenAmountToBigNumber("123", decimals); const expectedShareAmount = depositAmount .mul(BigNumber.from(10).pow(18)) .div(BigNumber.from(10).pow(decimals)); - await assetMock.mock.balanceOf.returns(9999); + await asset.mock.balanceOf.returns(9999); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedShareAmount ); // result doesn't depend on vault's asset balance - await assetMock.mock.balanceOf.withArgs(indexToken.address).returns(0); + await asset.mock.balanceOf.withArgs(indexToken.address).returns(0); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedShareAmount ); // result doesn't depend on vault's deployed value - await oracleAdapterMock.mock.getTvl.returns(10000000); + await oracleAdapter.mock.getTvl.returns(10000000); expect(await indexToken.convertToShares(depositAmount)).to.equal( expectedShareAmount ); @@ -686,9 +706,9 @@ describe("Contract: IndexToken", () => { const depositAmount = tokenAmountToBigNumber("1000", decimals); const vaultBalance = tokenAmountToBigNumber("9999", decimals); - await oracleAdapterMock.mock.getAssetPrice.returns(1); - await assetMock.mock.balanceOf.returns(vaultBalance); - await assetMock.mock.decimals.returns(decimals); + await oracleAdapter.mock.getAssetPrice.returns(1); + await asset.mock.balanceOf.returns(vaultBalance); + await asset.mock.decimals.returns(decimals); await indexToken.testMint(indexToken.address, aptTotalSupply); const expectedMintAmount = aptTotalSupply @@ -707,13 +727,11 @@ describe("Contract: IndexToken", () => { const vaultAssetBalance = tokenAmountToBigNumber("9999", decimals); const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); - await assetMock.mock.balanceOf.returns(vaultAssetBalance); - await assetMock.mock.decimals.returns(decimals); + await oracleAdapter.mock.getAssetPrice.returns(price); + await asset.mock.balanceOf.returns(vaultAssetBalance); + await asset.mock.decimals.returns(decimals); - await oracleAdapterMock.mock.getTvl.returns( - tokenAmountToBigNumber(10000000) - ); + await oracleAdapter.mock.getTvl.returns(tokenAmountToBigNumber(10000000)); await indexToken.testMint(indexToken.address, aptTotalSupply); @@ -730,14 +748,14 @@ describe("Contract: IndexToken", () => { describe("convertToAssets", () => { beforeEach(async () => { - await oracleAdapterMock.mock.getTvl.returns(0); + await oracleAdapter.mock.getTvl.returns(0); }); it("Convert 1:1 on zero total supply", async () => { expect(await indexToken.totalSupply()).to.equal(0); const decimals = 6; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const shareAmount = tokenAmountToBigNumber("123"); const expectedAssetAmount = shareAmount @@ -757,9 +775,9 @@ describe("Contract: IndexToken", () => { it("Returns expected amount", async () => { const decimals = 6; const assetBalance = tokenAmountToBigNumber(250, decimals); - await assetMock.mock.balanceOf.returns(assetBalance); - await assetMock.mock.decimals.returns(decimals); - await oracleAdapterMock.mock.getAssetPrice.returns( + await asset.mock.balanceOf.returns(assetBalance); + await asset.mock.decimals.returns(decimals); + await oracleAdapter.mock.getAssetPrice.returns( tokenAmountToBigNumber("1.02", 8) ); @@ -877,7 +895,7 @@ describe("Contract: IndexToken", () => { }); it("Revert if allowance is less than deposit", async () => { - await assetMock.mock.allowance.returns(0); + await asset.mock.allowance.returns(0); await expect(indexToken.deposit(1, receiver.address)).to.be.revertedWith( "ALLOWANCE_INSUFFICIENT" ); @@ -887,12 +905,12 @@ describe("Contract: IndexToken", () => { beforeEach(async () => { // These get rollbacked due to snapshotting. // Just enough mocking to get `deposit` to not revert. - await oracleAdapterMock.mock.getTvl.returns(0); - await oracleAdapterMock.mock.getAssetPrice.returns(1); - await assetMock.mock.decimals.returns(6); - await assetMock.mock.allowance.returns(1); - await assetMock.mock.balanceOf.returns(1); - await assetMock.mock.transferFrom.returns(true); + await oracleAdapter.mock.getTvl.returns(0); + await oracleAdapter.mock.getAssetPrice.returns(1); + await asset.mock.decimals.returns(6); + await asset.mock.allowance.returns(1); + await asset.mock.balanceOf.returns(1); + await asset.mock.transferFrom.returns(true); }); it("Save deposit time for receiver", async () => { @@ -925,10 +943,10 @@ describe("Contract: IndexToken", () => { it("previewRedeem returns expected amount", async () => { const decimals = 18; - await assetMock.mock.decimals.returns(decimals); + await asset.mock.decimals.returns(decimals); const depositAmount = tokenAmountToBigNumber("1", decimals); - await assetMock.mock.allowance.returns(depositAmount); - await assetMock.mock.balanceOf.returns(depositAmount); + await asset.mock.allowance.returns(depositAmount); + await asset.mock.balanceOf.returns(depositAmount); await indexToken.testMint( deployer.address, tokenAmountToBigNumber("1000") @@ -1001,17 +1019,17 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); - await assetMock.mock.decimals.returns(decimals); - await assetMock.mock.allowance.returns(depositAmount); - await assetMock.mock.balanceOf + await asset.mock.decimals.returns(decimals); + await asset.mock.allowance.returns(depositAmount); + await asset.mock.balanceOf .withArgs(indexToken.address) .returns(vaultBalance); - await assetMock.mock.transferFrom.returns(true); + await asset.mock.transferFrom.returns(true); }); after(async () => { @@ -1037,7 +1055,7 @@ describe("Contract: IndexToken", () => { // mock the asset transfer to the vault, so we can // check deposit event has the post-deposit vault ETH value - await assetMock.mock.balanceOf + await asset.mock.balanceOf .withArgs(indexToken.address) .returns(vaultBalance.add(depositAmount)); @@ -1069,13 +1087,13 @@ describe("Contract: IndexToken", () => { * * Instead, we have to do some hacky revert-check logic. */ - await assetMock.mock.transferFrom.revertsWithReason("FAIL_TEST"); + await asset.mock.transferFrom.revertsWithReason("FAIL_TEST"); await expect( indexToken .connect(randomUser) .deposit(depositAmount, receiver.address) ).to.be.revertedWith("FAIL_TEST"); - await assetMock.mock.transferFrom + await asset.mock.transferFrom .withArgs(randomUser.address, indexToken.address, depositAmount) .returns(true); await expect( @@ -1086,8 +1104,10 @@ describe("Contract: IndexToken", () => { }); it("Deposit should work after unlock", async () => { - await indexToken.connect(emergencySafe).emergencyLockDeposit(); - await indexToken.connect(emergencySafe).emergencyUnlockDeposit(); + await indexToken.connect(emergencySafeSigner).emergencyLockDeposit(); + await indexToken + .connect(emergencySafeSigner) + .emergencyUnlockDeposit(); await expect( indexToken @@ -1101,13 +1121,13 @@ describe("Contract: IndexToken", () => { describe("Locking", () => { it("Emergency Safe can lock", async () => { await expect( - indexToken.connect(emergencySafe).emergencyLockDeposit() + indexToken.connect(emergencySafeSigner).emergencyLockDeposit() ).to.emit(indexToken, "DepositLocked"); }); it("Emergency Safe can unlock", async () => { await expect( - indexToken.connect(emergencySafe).emergencyUnlockDeposit() + indexToken.connect(emergencySafeSigner).emergencyUnlockDeposit() ).to.emit(indexToken, "DepositUnlocked"); }); @@ -1124,7 +1144,7 @@ describe("Contract: IndexToken", () => { }); it("Revert deposit when vault is locked", async () => { - await indexToken.connect(emergencySafe).emergencyLockDeposit(); + await indexToken.connect(emergencySafeSigner).emergencyLockDeposit(); await expect( indexToken.connect(randomUser).deposit(1, receiver.address) @@ -1141,8 +1161,8 @@ describe("Contract: IndexToken", () => { }); it("Revert if allowance is less than deposit", async () => { - await assetMock.mock.decimals.returns(6); // needed to get to check - await assetMock.mock.allowance.returns(0); + await asset.mock.decimals.returns(6); // needed to get to check + await asset.mock.allowance.returns(0); await expect(indexToken.mint(1, receiver.address)).to.be.revertedWith( "ALLOWANCE_INSUFFICIENT" ); @@ -1152,12 +1172,12 @@ describe("Contract: IndexToken", () => { beforeEach(async () => { // These get rollbacked due to snapshotting. // Just enough mocking to get `mint` to not revert. - await oracleAdapterMock.mock.getTvl.returns(0); - await oracleAdapterMock.mock.getAssetPrice.returns(1); - await assetMock.mock.decimals.returns(6); - await assetMock.mock.allowance.returns(2); // account for rounding up in previewMint - await assetMock.mock.balanceOf.returns(1); - await assetMock.mock.transferFrom.returns(true); + await oracleAdapter.mock.getTvl.returns(0); + await oracleAdapter.mock.getAssetPrice.returns(1); + await asset.mock.decimals.returns(6); + await asset.mock.allowance.returns(2); // account for rounding up in previewMint + await asset.mock.balanceOf.returns(1); + await asset.mock.transferFrom.returns(true); }); it("Save deposit time for receiver", async () => { @@ -1214,19 +1234,19 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); - await assetMock.mock.decimals.returns(decimals); - await assetMock.mock.balanceOf + await asset.mock.decimals.returns(decimals); + await asset.mock.balanceOf .withArgs(indexToken.address) .returns(vaultBalance); - await assetMock.mock.transferFrom.returns(true); + await asset.mock.transferFrom.returns(true); depositAmount = await indexToken.previewMint(mintAmount); - await assetMock.mock.allowance.returns(depositAmount); + await asset.mock.allowance.returns(depositAmount); }); after(async () => { @@ -1268,11 +1288,11 @@ describe("Contract: IndexToken", () => { * * Instead, we have to do some hacky revert-check logic. */ - await assetMock.mock.transferFrom.revertsWithReason("FAIL_TEST"); + await asset.mock.transferFrom.revertsWithReason("FAIL_TEST"); await expect( indexToken.connect(randomUser).mint(mintAmount, receiver.address) ).to.be.revertedWith("FAIL_TEST"); - await assetMock.mock.transferFrom + await asset.mock.transferFrom .withArgs(randomUser.address, indexToken.address, depositAmount) .returns(true); await expect( @@ -1281,12 +1301,14 @@ describe("Contract: IndexToken", () => { }); it("Deposit should work after unlock", async () => { - await indexToken.connect(emergencySafe).emergencyLockDeposit(); + await indexToken.connect(emergencySafeSigner).emergencyLockDeposit(); await expect( indexToken.connect(randomUser).mint(1, receiver.address) ).to.be.revertedWith("LOCKED"); - await indexToken.connect(emergencySafe).emergencyUnlockDeposit(); + await indexToken + .connect(emergencySafeSigner) + .emergencyUnlockDeposit(); await expect( indexToken.connect(randomUser).mint(mintAmount, receiver.address) @@ -1338,17 +1360,17 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); - await assetMock.mock.decimals.returns(decimals); - await assetMock.mock.allowance.returns(vaultBalance); - await assetMock.mock.balanceOf + await asset.mock.decimals.returns(decimals); + await asset.mock.allowance.returns(vaultBalance); + await asset.mock.balanceOf .withArgs(indexToken.address) .returns(vaultBalance); - await assetMock.mock.transfer.returns(true); + await asset.mock.transfer.returns(true); // Mint APT supply to go along with vault's total ETH value. await indexToken.testMint(deployer.address, aptSupply); @@ -1430,13 +1452,13 @@ describe("Contract: IndexToken", () => { const assetAmount = await indexToken[ "previewRedeem(uint256,address)" ](aptAmount, randomUser.address); - await assetMock.mock.transfer.revertsWithReason("FAIL_TEST"); + await asset.mock.transfer.revertsWithReason("FAIL_TEST"); await expect( indexToken .connect(randomUser) .redeem(aptAmount, receiver.address, randomUser.address) ).to.be.revertedWith("FAIL_TEST"); - await assetMock.mock.transfer + await asset.mock.transfer .withArgs(receiver.address, assetAmount) .returns(true); await expect( @@ -1447,8 +1469,8 @@ describe("Contract: IndexToken", () => { }); it("Redeem should work after unlock", async () => { - await indexToken.connect(emergencySafe).emergencyLockRedeem(); - await indexToken.connect(emergencySafe).emergencyUnlockRedeem(); + await indexToken.connect(emergencySafeSigner).emergencyLockRedeem(); + await indexToken.connect(emergencySafeSigner).emergencyUnlockRedeem(); await expect( indexToken @@ -1485,13 +1507,13 @@ describe("Contract: IndexToken", () => { describe("Locking", () => { it("Emergency Safe can lock", async () => { await expect( - indexToken.connect(emergencySafe).emergencyLockRedeem() + indexToken.connect(emergencySafeSigner).emergencyLockRedeem() ).to.emit(indexToken, "RedeemLocked"); }); it("Emergency Safe can unlock", async () => { await expect( - indexToken.connect(emergencySafe).emergencyUnlockRedeem() + indexToken.connect(emergencySafeSigner).emergencyUnlockRedeem() ).to.emit(indexToken, "RedeemUnlocked"); }); @@ -1508,7 +1530,7 @@ describe("Contract: IndexToken", () => { }); it("Revert redeem when vault is locked", async () => { - await indexToken.connect(emergencySafe).emergencyLockRedeem(); + await indexToken.connect(emergencySafeSigner).emergencyLockRedeem(); await expect( indexToken @@ -1553,17 +1575,17 @@ describe("Contract: IndexToken", () => { const snapshot = await timeMachine.takeSnapshot(); snapshotId = snapshot["result"]; - await oracleAdapterMock.mock.getTvl.returns(deployedValue); + await oracleAdapter.mock.getTvl.returns(deployedValue); const price = 1; - await oracleAdapterMock.mock.getAssetPrice.returns(price); + await oracleAdapter.mock.getAssetPrice.returns(price); - await assetMock.mock.decimals.returns(decimals); - await assetMock.mock.allowance.returns(vaultBalance); - await assetMock.mock.balanceOf + await asset.mock.decimals.returns(decimals); + await asset.mock.allowance.returns(vaultBalance); + await asset.mock.balanceOf .withArgs(indexToken.address) .returns(vaultBalance); - await assetMock.mock.transfer.returns(true); + await asset.mock.transfer.returns(true); // Mint APT supply to go along with vault's total ETH value. await indexToken.testMint(deployer.address, aptSupply); @@ -1671,13 +1693,13 @@ describe("Contract: IndexToken", () => { * * Instead, we have to do some hacky revert-check logic. */ - await assetMock.mock.transfer.revertsWithReason("FAIL_TEST"); + await asset.mock.transfer.revertsWithReason("FAIL_TEST"); await expect( indexToken .connect(randomUser) .withdraw(assetAmount, receiver.address, randomUser.address) ).to.be.revertedWith("FAIL_TEST"); - await assetMock.mock.transfer + await asset.mock.transfer .withArgs(receiver.address, assetAmount) .returns(true); await expect( @@ -1688,8 +1710,8 @@ describe("Contract: IndexToken", () => { }); it("Withdraw should work after unlock", async () => { - await indexToken.connect(emergencySafe).emergencyLockRedeem(); - await indexToken.connect(emergencySafe).emergencyUnlockRedeem(); + await indexToken.connect(emergencySafeSigner).emergencyLockRedeem(); + await indexToken.connect(emergencySafeSigner).emergencyUnlockRedeem(); await expect( indexToken @@ -1714,7 +1736,7 @@ describe("Contract: IndexToken", () => { describe("Locking", () => { it("Revert withdraw when vault is locked", async () => { - await indexToken.connect(emergencySafe).emergencyLockRedeem(); + await indexToken.connect(emergencySafeSigner).emergencyLockRedeem(); await expect( indexToken From 80e5254aacee0776f69ad3ca96f640b35c72d06e Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Wed, 10 Aug 2022 16:05:33 -0400 Subject: [PATCH 16/16] Test new storage vars set --- test-unit/IndexToken.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test-unit/IndexToken.js b/test-unit/IndexToken.js index b2bc4d9d..b2d011c1 100644 --- a/test-unit/IndexToken.js +++ b/test-unit/IndexToken.js @@ -16,7 +16,7 @@ const { const IDetailedERC20 = artifacts.require("IDetailedERC20"); const OracleAdapter = artifacts.require("OracleAdapter"); -describe.only("Contract: IndexToken", () => { +describe("Contract: IndexToken", () => { // signers let deployer; let adminSafeSigner; @@ -155,6 +155,14 @@ describe.only("Contract: IndexToken", () => { .be.true; }); + it("Oracle Adapter set correctly", async () => { + expect(await indexToken.oracleAdapter()).to.equal(oracleAdapter.address); + }); + + it("LP Account set correctly", async () => { + expect(await indexToken.lpAccount()).to.equal(lpAccount.address); + }); + it("Name set to correct value", async () => { expect(await indexToken.name()).to.equal("Convex Index Token"); });