From 90ecf25a20ca3924bbb2c0fed5ca378fc2a2cfae Mon Sep 17 00:00:00 2001 From: Carl Farterson Date: Wed, 15 Dec 2021 15:08:54 -0800 Subject: [PATCH] feat: add tests/setup so file can be tested individually --- .../migrations/UniswapSingleTransfer.ts | 619 +++++++++--------- 1 file changed, 316 insertions(+), 303 deletions(-) diff --git a/test/contracts/migrations/UniswapSingleTransfer.ts b/test/contracts/migrations/UniswapSingleTransfer.ts index f87d6274..eda8b0a9 100644 --- a/test/contracts/migrations/UniswapSingleTransfer.ts +++ b/test/contracts/migrations/UniswapSingleTransfer.ts @@ -18,345 +18,358 @@ import { hubSetup } from "../../utils/hubSetup"; import { expect } from "chai"; import { Fees } from "../../../artifacts/types/Fees"; -describe("UniswapSingleTransferMigration.sol", () => { - let earliestSwapTime: number; - let DAI: string; - let WETH: string; - let DAIWhale: string; - let WETHWhale: string; - let daiHolder: Signer; - let wethHolder: Signer; - let dai: ERC20; - let weth: ERC20; - let account0: SignerWithAddress; - let account1: SignerWithAddress; - let account2: SignerWithAddress; - let migrationRegistry: MigrationRegistry; - let migration: UniswapSingleTransferMigration; - let curve: BancorABDK; - let meTokenRegistry: MeTokenRegistry; - let singleAssetVault: SingleAssetVault; - let foundry: Foundry; - let meToken: MeToken; - let hub: Hub; - let fee: Fees; +const setup = async () => { + describe("UniswapSingleTransferMigration.sol", () => { + let earliestSwapTime: number; + let DAI: string; + let WETH: string; + let DAIWhale: string; + let WETHWhale: string; + let daiHolder: Signer; + let wethHolder: Signer; + let dai: ERC20; + let weth: ERC20; + let account0: SignerWithAddress; + let account1: SignerWithAddress; + let account2: SignerWithAddress; + let migrationRegistry: MigrationRegistry; + let migration: UniswapSingleTransferMigration; + let curve: BancorABDK; + let meTokenRegistry: MeTokenRegistry; + let singleAssetVault: SingleAssetVault; + let foundry: Foundry; + let meToken: MeToken; + let hub: Hub; + let fee: Fees; - const hubId1 = 1; - const hubId2 = 2; - const name = "Carl meToken"; - const symbol = "CARL"; - const amount = ethers.utils.parseEther("100"); - const fees = 3000; - const refundRatio = 500000; - const MAX_WEIGHT = 1000000; - const reserveWeight = MAX_WEIGHT / 2; - const PRECISION = BigNumber.from(10).pow(6); - const baseY = PRECISION.div(1000).toString(); + const hubId1 = 1; + const hubId2 = 2; + const name = "Carl meToken"; + const symbol = "CARL"; + const amount = ethers.utils.parseEther("100"); + const fees = 3000; + const refundRatio = 500000; + const MAX_WEIGHT = 1000000; + const reserveWeight = MAX_WEIGHT / 2; + const PRECISION = BigNumber.from(10).pow(6); + const baseY = PRECISION.div(1000).toString(); - let encodedCurveDetails: string; - let encodedMigrationArgs: string; - let badEncodedMigrationArgs: string; - let encodedVaultDAIArgs: string; - let encodedVaultWETHArgs: string; - let block; - let details: [BigNumber, number, boolean, boolean, boolean] & { - soonest: BigNumber; - fee: number; - started: boolean; - swapped: boolean; - finished: boolean; - }; + let encodedCurveDetails: string; + let encodedMigrationArgs: string; + let badEncodedMigrationArgs: string; + let encodedVaultDAIArgs: string; + let encodedVaultWETHArgs: string; + let block; + let details: [BigNumber, number, boolean, boolean, boolean] & { + soonest: BigNumber; + fee: number; + started: boolean; + swapped: boolean; + finished: boolean; + }; - before(async () => { - ({ DAI, DAIWhale, WETH, WETHWhale } = await getNamedAccounts()); - encodedCurveDetails = ethers.utils.defaultAbiCoder.encode( - ["uint256", "uint32"], - [baseY, reserveWeight] - ); - encodedVaultDAIArgs = ethers.utils.defaultAbiCoder.encode( - ["address"], - [DAI] - ); - encodedVaultWETHArgs = ethers.utils.defaultAbiCoder.encode( - ["address"], - [WETH] - ); - - const block = await ethers.provider.getBlock("latest"); - earliestSwapTime = block.timestamp + 600 * 60; // 10h in future - - encodedMigrationArgs = ethers.utils.defaultAbiCoder.encode( - ["uint256", "uint24"], - [earliestSwapTime, fees] - ); + before(async () => { + ({ DAI, DAIWhale, WETH, WETHWhale } = await getNamedAccounts()); + encodedCurveDetails = ethers.utils.defaultAbiCoder.encode( + ["uint256", "uint32"], + [baseY, reserveWeight] + ); + encodedVaultDAIArgs = ethers.utils.defaultAbiCoder.encode( + ["address"], + [DAI] + ); + encodedVaultWETHArgs = ethers.utils.defaultAbiCoder.encode( + ["address"], + [WETH] + ); - curve = await deploy("BancorABDK"); - ({ - hub, - migrationRegistry, - singleAssetVault, - foundry, - account0, - account1, - account2, - meTokenRegistry, - fee, - } = await hubSetup( - encodedCurveDetails, - encodedVaultDAIArgs, - refundRatio, - curve - )); - // Register 2nd hub to which we'll migrate to - await hub.register( - account0.address, - WETH, - singleAssetVault.address, - curve.address, - refundRatio, - encodedCurveDetails, - encodedVaultWETHArgs - ); - // Deploy uniswap migration and approve it to the registry - migration = await deploy( - "UniswapSingleTransferMigration", - undefined, - account0.address, - foundry.address, - hub.address, - meTokenRegistry.address, - migrationRegistry.address - ); - await migrationRegistry.approve( - singleAssetVault.address, - singleAssetVault.address, - migration.address - ); - // Pre fund owner & buyer w/ DAI & WETH - dai = await getContractAt("ERC20", DAI); - weth = await getContractAt("ERC20", WETH); - daiHolder = await impersonate(DAIWhale); - wethHolder = await impersonate(WETHWhale); - dai - .connect(daiHolder) - .transfer(account0.address, ethers.utils.parseEther("100")); - dai - .connect(daiHolder) - .transfer(account2.address, ethers.utils.parseEther("1000")); - weth - .connect(wethHolder) - .transfer(account0.address, ethers.utils.parseEther("10")); - weth - .connect(wethHolder) - .transfer(account2.address, ethers.utils.parseEther("100")); - await dai.connect(account1).approve(meTokenRegistry.address, amount); - // Create meToken - await meTokenRegistry - .connect(account1) - .subscribe(name, symbol, hubId1, amount); - const meTokenAddr = await meTokenRegistry.getOwnerMeToken(account1.address); - meToken = await getContractAt("MeToken", meTokenAddr); - }); + const block = await ethers.provider.getBlock("latest"); + earliestSwapTime = block.timestamp + 600 * 60; // 10h in future - describe("isValid()", () => { - it("Returns false for invalid encoding", async () => { - const isValid = await migration.isValid(meToken.address, "0x"); - expect(isValid).to.be.false; - }); - it("Returns true for valid encoding", async () => { - const isValid = await migration.isValid( - meToken.address, - encodedMigrationArgs - ); - expect(isValid).to.be.true; - }); - it("Returns false for start time before current time", async () => { - badEncodedMigrationArgs = ethers.utils.defaultAbiCoder.encode( + encodedMigrationArgs = ethers.utils.defaultAbiCoder.encode( ["uint256", "uint24"], - [earliestSwapTime - 720 * 60, fees] // 2 hours beforehand + [earliestSwapTime, fees] ); - const isValid = await migration.isValid( - meToken.address, - badEncodedMigrationArgs + + curve = await deploy("BancorABDK"); + ({ + hub, + migrationRegistry, + singleAssetVault, + foundry, + account0, + account1, + account2, + meTokenRegistry, + fee, + } = await hubSetup( + encodedCurveDetails, + encodedVaultDAIArgs, + refundRatio, + curve + )); + // Register 2nd hub to which we'll migrate to + await hub.register( + account0.address, + WETH, + singleAssetVault.address, + curve.address, + refundRatio, + encodedCurveDetails, + encodedVaultWETHArgs ); - expect(isValid).to.be.false; - }); - it("Returns false for nonexistent meToken", async () => { - const isValid = await migration.isValid( + // Deploy uniswap migration and approve it to the registry + migration = await deploy( + "UniswapSingleTransferMigration", + undefined, account0.address, - encodedMigrationArgs + foundry.address, + hub.address, + meTokenRegistry.address, + migrationRegistry.address ); - expect(isValid).to.be.false; - }); - it("Returns false for invalid fee", async () => { - badEncodedMigrationArgs = ethers.utils.defaultAbiCoder.encode( - ["uint256", "uint24"], - [earliestSwapTime, 2999] + await migrationRegistry.approve( + singleAssetVault.address, + singleAssetVault.address, + migration.address ); - const isValid = await migration.isValid( - meToken.address, - badEncodedMigrationArgs + // Pre fund owner & buyer w/ DAI & WETH + dai = await getContractAt("ERC20", DAI); + weth = await getContractAt("ERC20", WETH); + daiHolder = await impersonate(DAIWhale); + wethHolder = await impersonate(WETHWhale); + dai + .connect(daiHolder) + .transfer(account0.address, ethers.utils.parseEther("100")); + dai + .connect(daiHolder) + .transfer(account2.address, ethers.utils.parseEther("1000")); + weth + .connect(wethHolder) + .transfer(account0.address, ethers.utils.parseEther("10")); + weth + .connect(wethHolder) + .transfer(account2.address, ethers.utils.parseEther("100")); + await dai.connect(account1).approve(meTokenRegistry.address, amount); + // Create meToken + await meTokenRegistry + .connect(account1) + .subscribe(name, symbol, hubId1, amount); + const meTokenAddr = await meTokenRegistry.getOwnerMeToken( + account1.address ); - expect(isValid).to.be.false; + meToken = await getContractAt("MeToken", meTokenAddr); }); - }); - describe("initMigration()", () => { - it("Reverts when sender is not meTokenRegistry", async () => { - await expect( - migration.initMigration(meToken.address, encodedMigrationArgs) - ).to.be.revertedWith("!meTokenRegistry"); + describe("isValid()", () => { + it("Returns false for invalid encoding", async () => { + const isValid = await migration.isValid(meToken.address, "0x"); + expect(isValid).to.be.false; + }); + it("Returns true for valid encoding", async () => { + const isValid = await migration.isValid( + meToken.address, + encodedMigrationArgs + ); + expect(isValid).to.be.true; + }); + it("Returns false for start time before current time", async () => { + badEncodedMigrationArgs = ethers.utils.defaultAbiCoder.encode( + ["uint256", "uint24"], + [earliestSwapTime - 720 * 60, fees] // 2 hours beforehand + ); + const isValid = await migration.isValid( + meToken.address, + badEncodedMigrationArgs + ); + expect(isValid).to.be.false; + }); + it("Returns false for nonexistent meToken", async () => { + const isValid = await migration.isValid( + account0.address, + encodedMigrationArgs + ); + expect(isValid).to.be.false; + }); + it("Returns false for invalid fee", async () => { + badEncodedMigrationArgs = ethers.utils.defaultAbiCoder.encode( + ["uint256", "uint24"], + [earliestSwapTime, 2999] + ); + const isValid = await migration.isValid( + meToken.address, + badEncodedMigrationArgs + ); + expect(isValid).to.be.false; + }); }); - it("Fails from bad encodings", async () => { - await expect( - meTokenRegistry + + describe("initMigration()", () => { + it("Reverts when sender is not meTokenRegistry", async () => { + await expect( + migration.initMigration(meToken.address, encodedMigrationArgs) + ).to.be.revertedWith("!meTokenRegistry"); + }); + it("Fails from bad encodings", async () => { + await expect( + meTokenRegistry + .connect(account1) + .initResubscribe( + meToken.address, + hubId2, + migration.address, + badEncodedMigrationArgs + ) + ).to.be.revertedWith("Invalid _encodedMigrationArgs"); + }); + it("Set correct _ust values", async () => { + await meTokenRegistry .connect(account1) .initResubscribe( meToken.address, hubId2, migration.address, - badEncodedMigrationArgs - ) - ).to.be.revertedWith("Invalid _encodedMigrationArgs"); + encodedMigrationArgs + ); + const migrationDetails = await migration.getDetails(meToken.address); + expect(migrationDetails.fee).to.equal(fees); + expect(migrationDetails.soonest).to.equal(earliestSwapTime); + }); }); - it("Set correct _ust values", async () => { - await meTokenRegistry - .connect(account1) - .initResubscribe( - meToken.address, - hubId2, - migration.address, - encodedMigrationArgs - ); - const migrationDetails = await migration.getDetails(meToken.address); - expect(migrationDetails.fee).to.equal(fees); - expect(migrationDetails.soonest).to.equal(earliestSwapTime); - }); - }); - describe("poke()", () => { - it("should be able to call before soonest, but wont run startMigration()", async () => { - details = await migration.getDetails(meToken.address); - block = await ethers.provider.getBlock("latest"); - expect(details.soonest).to.be.gt(block.timestamp); + describe("poke()", () => { + it("should be able to call before soonest, but wont run startMigration()", async () => { + details = await migration.getDetails(meToken.address); + block = await ethers.provider.getBlock("latest"); + expect(details.soonest).to.be.gt(block.timestamp); - const tx = await migration.poke(meToken.address); - await tx.wait(); + const tx = await migration.poke(meToken.address); + await tx.wait(); - await expect(tx).to.not.emit(singleAssetVault, "StartMigration"); - details = await migration.getDetails(meToken.address); - expect(details.started).to.be.equal(false); - }); - it("Triggers startMigration()", async () => { - await mineBlock(details.soonest.toNumber() + 1); - block = await ethers.provider.getBlock("latest"); - expect(details.soonest).to.be.lt(block.timestamp); + await expect(tx).to.not.emit(singleAssetVault, "StartMigration"); + details = await migration.getDetails(meToken.address); + expect(details.started).to.be.equal(false); + }); + it("Triggers startMigration()", async () => { + await mineBlock(details.soonest.toNumber() + 1); + block = await ethers.provider.getBlock("latest"); + expect(details.soonest).to.be.lt(block.timestamp); - const tx = await migration.poke(meToken.address); - await tx.wait(); + const tx = await migration.poke(meToken.address); + await tx.wait(); - await expect(tx) - .to.emit(singleAssetVault, "StartMigration") - .withArgs(meToken.address) - // TODO check updated balance here - .to.emit(meTokenRegistry, "UpdateBalances"); - details = await migration.getDetails(meToken.address); - expect(details.started).to.be.equal(true); - expect(details.swapped).to.be.equal(true); + await expect(tx) + .to.emit(singleAssetVault, "StartMigration") + .withArgs(meToken.address) + // TODO check updated balance here + .to.emit(meTokenRegistry, "UpdateBalances"); + details = await migration.getDetails(meToken.address); + expect(details.started).to.be.equal(true); + expect(details.swapped).to.be.equal(true); + }); }); - }); - describe("finishMigration()", () => { - it("Reverts when sender is not meTokenRegistry", async () => { - await expect( - migration.finishMigration(meToken.address) - ).to.be.revertedWith("!meTokenRegistry"); - }); - xit("Triggers startsMigration() if it hasn't already started", async () => { - // fast-forward 24h to when finishMigration() can be called - let block = await ethers.provider.getBlock("latest"); - await mineBlock(block.timestamp + 24 * 60); + describe("finishMigration()", () => { + it("Reverts when sender is not meTokenRegistry", async () => { + await expect( + migration.finishMigration(meToken.address) + ).to.be.revertedWith("!meTokenRegistry"); + }); + xit("Triggers startsMigration() if it hasn't already started", async () => { + // fast-forward 24h to when finishMigration() can be called + let block = await ethers.provider.getBlock("latest"); + await mineBlock(block.timestamp + 24 * 60); + }); + describe("During resubscribe", () => { + xit("From warmup => startTime: assets transferred to/from initial vault", async () => {}); + xit("From startTime => soonest: assets transferred to/from initial vault", async () => {}); + xit("From soonest => endTime: assets transferred to/from migration vault", async () => {}); + xit("After endTime: assets transferred to/from target vault", async () => {}); + }); }); }); - // it("", async () => { +}; - // const balBefore = await dai.balanceOf(account0.address); +setup().then(() => { + run(); +}); - // // need an approve of metoken registry first - // await dai.approve(foundry.address, amount); - // await foundry.mint(meToken.address, amount, account2.address); +// const balBefore = await dai.balanceOf(account0.address); - // const meTokenDetails = await meTokenRegistry.getDetails(meToken.address); +// // need an approve of metoken registry first +// await dai.approve(foundry.address, amount); +// await foundry.mint(meToken.address, amount, account2.address); - // }); - // it("burn() from buyer should work", async () => { - // await foundry - // .connect(account2) - // .burn(meToken.address, balBefore, account2.address); - // }); - // describe("during migration", () => { - // before(async () => { - // // migrate meToken - // // refund ratio stays the same - // const targetRefundRatio = 200000; +// const meTokenDetails = await meTokenRegistry.getDetails(meToken.address); - // // 10 hour - // await hub.setDuration(600 * 60); - // await hub.setWarmup(60 * 60); - // await hub.setCooldown(60 * 60); - // // vault stays the same - // }); - // it("After migration, mint() takes WETH deposited", async () => { +// }); +// it("burn() from buyer should work", async () => { +// await foundry +// .connect(account2) +// .burn(meToken.address, balBefore, account2.address); +// }); +// describe("during migration", () => { +// before(async () => { +// // migrate meToken +// // refund ratio stays the same +// const targetRefundRatio = 200000; - // }); - // it("burn() Should work", async () => { - // const balBefore = await meToken.balanceOf(account2.address); - // const balDaiBefore = await dai.balanceOf(account2.address); +// // 10 hour +// await hub.setDuration(600 * 60); +// await hub.setWarmup(60 * 60); +// await hub.setCooldown(60 * 60); +// // vault stays the same +// }); +// it("After migration, mint() takes WETH deposited", async () => { - // const hubDetail = await hub.getDetails(hubId1); - // const balVaultBefore = await dai.balanceOf(hubDetail.vault); - // await foundry - // .connect(account2) - // .burn(meToken.address, balBefore, account2.address); - // const balAfter = await meToken.balanceOf(account2.address); - // const balDaiAfter = await dai.balanceOf(account2.address); - // expect(balAfter).equal(0); - // expect(await meToken.totalSupply()).to.equal(0); - // expect(balDaiAfter).to.be.gt(balDaiBefore); +// }); +// it("burn() Should work", async () => { +// const balBefore = await meToken.balanceOf(account2.address); +// const balDaiBefore = await dai.balanceOf(account2.address); - // const balVaultAfter = await dai.balanceOf(hubDetail.vault); - // expect(balVaultBefore.sub(balVaultAfter)).equal( - // balDaiAfter.sub(balDaiBefore) - // ); - // }); - // it("mint() Should work after some time during the migration ", async () => { - // // metoken should be registered - // let block = await ethers.provider.getBlock("latest"); - // await mineBlock(block.timestamp + 60 * 60); +// const hubDetail = await hub.getDetails(hubId1); +// const balVaultBefore = await dai.balanceOf(hubDetail.vault); +// await foundry +// .connect(account2) +// .burn(meToken.address, balBefore, account2.address); +// const balAfter = await meToken.balanceOf(account2.address); +// const balDaiAfter = await dai.balanceOf(account2.address); +// expect(balAfter).equal(0); +// expect(await meToken.totalSupply()).to.equal(0); +// expect(balDaiAfter).to.be.gt(balDaiBefore); - // const hubDetail = await hub.getDetails(hubId1); - // block = await ethers.provider.getBlock("latest"); - // expect(hubDetail.startTime).to.be.lt(block.timestamp); - // const balVaultBefore = await dai.balanceOf(hubDetail.vault); - // const balBefore = await dai.balanceOf(account2.address); - // // need an approve of metoken registry first - // await dai.connect(account2).approve(foundry.address, amount); - // await foundry - // .connect(account2) - // .mint(meToken.address, amount, account2.address); - // const balAfter = await dai.balanceOf(account2.address); - // expect(balBefore.sub(balAfter)).equal(amount); +// const balVaultAfter = await dai.balanceOf(hubDetail.vault); +// expect(balVaultBefore.sub(balVaultAfter)).equal( +// balDaiAfter.sub(balDaiBefore) +// ); +// }); +// it("mint() Should work after some time during the migration ", async () => { +// // metoken should be registered +// let block = await ethers.provider.getBlock("latest"); +// await mineBlock(block.timestamp + 60 * 60); - // const balVaultAfter = await dai.balanceOf(hubDetail.vault); - // expect(balVaultAfter).equal(balVaultBefore.add(amount)); - // // assert token infos - // const meTokenAddr = await meTokenRegistry.getOwnerMeToken( - // account0.address - // ); - // expect(meTokenAddr).to.equal(meToken.address); - // // should be greater than 0 - // expect(await meToken.totalSupply()).to.equal( - // await meToken.balanceOf(account2.address) - // ); - // }); - // }); -}); +// const hubDetail = await hub.getDetails(hubId1); +// block = await ethers.provider.getBlock("latest"); +// expect(hubDetail.startTime).to.be.lt(block.timestamp); +// const balVaultBefore = await dai.balanceOf(hubDetail.vault); +// const balBefore = await dai.balanceOf(account2.address); +// // need an approve of metoken registry first +// await dai.connect(account2).approve(foundry.address, amount); +// await foundry +// .connect(account2) +// .mint(meToken.address, amount, account2.address); +// const balAfter = await dai.balanceOf(account2.address); +// expect(balBefore.sub(balAfter)).equal(amount); + +// const balVaultAfter = await dai.balanceOf(hubDetail.vault); +// expect(balVaultAfter).equal(balVaultBefore.add(amount)); +// // assert token infos +// const meTokenAddr = await meTokenRegistry.getOwnerMeToken( +// account0.address +// ); +// expect(meTokenAddr).to.equal(meToken.address); +// // should be greater than 0 +// expect(await meToken.totalSupply()).to.equal( +// await meToken.balanceOf(account2.address) +// ); +// }); +// });