From 683f98c96c6a6da212a03a1d7adca66f3ea9a745 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 1 Aug 2020 16:08:27 +0800 Subject: [PATCH] fix test --- migrations/2_deploy.js | 10 +-- test/Admin.test.ts | 10 +-- test/Attacks.test.ts | 16 ++--- test/DODOEthProxy.test.ts | 1 - test/DODOZoo.test.ts | 28 +++++--- test/LiquidityProvider.test.ts | 50 ++++++------- test/LongTailTokenlMode.test.ts | 14 ++-- test/StableCoinMode.test.ts | 14 ++-- test/Trader.test.ts | 62 ++++++++--------- test/UniswapArbitrageur.test.ts | 120 ++++++++++++++++++++++++++++++++ test/utils/Context.ts | 9 +-- test/utils/Contracts.ts | 68 ++++++------------ 12 files changed, 251 insertions(+), 151 deletions(-) create mode 100644 test/UniswapArbitrageur.test.ts diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 39dc335..434e5b6 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -1,11 +1,3 @@ const DODOZoo = artifacts.require("DODOZoo"); -module.exports = async (deployer, network) => { - const deployDODOZoo = async () => { - await deployer.deploy(DODOZoo); - }; - - if (network == "development") { - await deployDODOZoo(); - } -}; +module.exports = async (deployer, network) => {}; diff --git a/test/Admin.test.ts b/test/Admin.test.ts index d9c60a5..0375223 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -108,12 +108,12 @@ describe("Admin", () => { await ctx.DODO.methods.disableTrading().send(ctx.sendParam(ctx.Supervisor)) await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)), /TRADE_NOT_ALLOWED/ ) await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)) - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("101")) }) @@ -194,7 +194,7 @@ describe("Admin", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") @@ -211,7 +211,7 @@ describe("Admin", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("100")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("100"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") @@ -232,7 +232,7 @@ describe("Admin", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) await assert.rejects( ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)), diff --git a/test/Attacks.test.ts b/test/Attacks.test.ts index 288f34b..21552bb 100644 --- a/test/Attacks.test.ts +++ b/test/Attacks.test.ts @@ -71,15 +71,15 @@ describe("Attacks", () => { // attack step 1 await ctx.DODO.methods.depositBase(decimalStr("5000")).send(ctx.sendParam(hacker)) // attack step 2 - await ctx.DODO.methods.buyBaseToken(decimalStr("9.5"), decimalStr("2000")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9.5"), decimalStr("2000"), "0x").send(ctx.sendParam(hacker)) // attack step 3 await ctx.DODO.methods.withdrawBase(decimalStr("5000")).send(ctx.sendParam(hacker)) // attack step 4 let hackerTempBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) if (hackerTempBaseBalance.isGreaterThan(hackerInitBaseBalance)) { - await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0").send(ctx.sendParam(hacker)) + await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0", "0x").send(ctx.sendParam(hacker)) } else { - await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000"), "0x").send(ctx.sendParam(hacker)) } // expected hacker no profit @@ -106,15 +106,15 @@ describe("Attacks", () => { // attack step 1 await ctx.DODO.methods.depositQuote(decimalStr("100000")).send(ctx.sendParam(hacker)) // attack step 2 - await ctx.DODO.methods.sellBaseToken(decimalStr("9"), decimalStr("500")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.sellBaseToken(decimalStr("9"), decimalStr("500"), "0x").send(ctx.sendParam(hacker)) // attack step 3 await ctx.DODO.methods.withdrawQuote(decimalStr("100000")).send(ctx.sendParam(hacker)) // attack step 4 let hackerTempBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) if (hackerTempBaseBalance.isGreaterThan(hackerInitBaseBalance)) { - await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0").send(ctx.sendParam(hacker)) + await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0", "0x").send(ctx.sendParam(hacker)) } else { - await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000"), "0x").send(ctx.sendParam(hacker)) } // expected hacker no profit @@ -145,10 +145,10 @@ describe("Attacks", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ ) await assert.rejects( - ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("200")).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("200"), "0x").send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ ) }) diff --git a/test/DODOEthProxy.test.ts b/test/DODOEthProxy.test.ts index 8be69d2..2bd6302 100644 --- a/test/DODOEthProxy.test.ts +++ b/test/DODOEthProxy.test.ts @@ -20,7 +20,6 @@ async function init(ctx: DODOContext): Promise { // switch ctx to eth proxy mode let WETH = await contracts.newContract(contracts.WETH_CONTRACT_NAME) await ctx.DODOZoo.methods.breedDODO( - ctx.Supervisor, ctx.Maintainer, WETH.options.address, ctx.QUOTE.options.address, diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index 9ebf82f..d275a5a 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -33,12 +33,12 @@ describe("DODO ZOO", () => { describe("Breed new dodo", () => { it("could not deploy the same dodo", async () => { await assert.rejects( - ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.BASE.options.address, ctx.QUOTE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, ctx.BASE.options.address, ctx.QUOTE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), /DODO_REGISTERED/ ) await assert.rejects( - ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), /DODO_REGISTERED/ ) }) @@ -47,27 +47,37 @@ describe("DODO ZOO", () => { let newBase = await newContract(TEST_ERC20_CONTRACT_NAME, ["AnotherBase", 18]) let newQuote = await newContract(TEST_ERC20_CONTRACT_NAME, ["AnotherQuote", 18]) await assert.rejects( - ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Maintainer)), + ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Maintainer)), /NOT_OWNER/ ) - await ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)) + await ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)) let newDODO = getContractWithAddress(DODO_CONTRACT_NAME, await ctx.DODOZoo.methods.getDODO(newBase.options.address, newQuote.options.address).call()) assert.equal(await newDODO.methods._BASE_TOKEN_().call(), newBase.options.address) assert.equal(await newDODO.methods._QUOTE_TOKEN_().call(), newQuote.options.address) - await newDODO.methods.claimOwnership().send(ctx.sendParam(ctx.Deployer)) - // could not init twice await assert.rejects( - newDODO.methods.init(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + newDODO.methods.init(ctx.Deployer, ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), /DODO_INITIALIZED/ ) + + // console.log(await ctx.DODOZoo.methods.getDODOs().call()) }) - it("remove dodo", async () => { - await ctx.DODOZoo.methods.removeDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + it("dodo register control flow", async () => { + await ctx.DODOZoo.methods.removeDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call(), "0x0000000000000000000000000000000000000000") + await assert.rejects( + ctx.DODOZoo.methods.removeDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)), + /DODO_NOT_REGISTERED/ + ) + await ctx.DODOZoo.methods.addDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call(), ctx.DODO.options.address) + await assert.rejects( + ctx.DODOZoo.methods.addDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)), + /DODO_REGISTERED/ + ) }) }) diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index 6a86353..fb149e2 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -90,7 +90,7 @@ describe("LiquidityProvider", () => { it("deposit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) @@ -113,7 +113,7 @@ describe("LiquidityProvider", () => { it("withdraw", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "1065045389392391665") assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") @@ -134,7 +134,7 @@ describe("LiquidityProvider", () => { it("deposit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1000978629616255276996") @@ -155,7 +155,7 @@ describe("LiquidityProvider", () => { it("withdraw", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "0") assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "7389428846238900753") @@ -176,7 +176,7 @@ describe("LiquidityProvider", () => { it("base side lp don't has pnl when R is BELOW ONE", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")); @@ -192,7 +192,7 @@ describe("LiquidityProvider", () => { it("quote side lp don't has pnl when R is ABOVE ONE", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("600")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("600"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")); @@ -250,8 +250,8 @@ describe("LiquidityProvider", () => { describe("Corner cases", () => { it("single side deposit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken("5015841132009222923", decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken("5015841132009222923", decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10010841132009222923") @@ -264,7 +264,7 @@ describe("LiquidityProvider", () => { it("single side deposit & lp deposit when R isn't equal to ONE", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) @@ -274,11 +274,11 @@ describe("LiquidityProvider", () => { it("single side deposit (base) & oracle change introduces loss", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("120")) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9234731968726215603") @@ -292,11 +292,11 @@ describe("LiquidityProvider", () => { it("single side deposit (base) & oracle change introduces profit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "11138732839027528584") @@ -310,11 +310,11 @@ describe("LiquidityProvider", () => { it("single side deposit (quote) & oracle change introduces loss", async () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")) - await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("600")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken(decimalStr("0.99"), decimalStr("500")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("600"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("0.99"), decimalStr("500"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9980000000000000") @@ -328,7 +328,7 @@ describe("LiquidityProvider", () => { it("deposit and withdraw immediately", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") @@ -347,7 +347,7 @@ describe("LiquidityProvider", () => { describe("Revert cases", () => { it("withdraw base amount exceeds DODO balance", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("6")).send(ctx.sendParam(lp1)), @@ -362,7 +362,7 @@ describe("LiquidityProvider", () => { it("withdraw quote amount exceeds DODO balance", async () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("600")).send(ctx.sendParam(lp1)), @@ -377,7 +377,7 @@ describe("LiquidityProvider", () => { it("withdraw base could not afford penalty", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp1)), @@ -392,7 +392,7 @@ describe("LiquidityProvider", () => { it("withdraw quote could not afford penalty", async () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp1)), @@ -408,7 +408,7 @@ describe("LiquidityProvider", () => { it("withdraw all base could not afford penalty", async () => { await ctx.DODO.methods.depositBase(decimalStr("9.5")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositBase(decimalStr("0.5")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp2)), @@ -419,7 +419,7 @@ describe("LiquidityProvider", () => { it("withdraw all quote could not afford penalty", async () => { await ctx.DODO.methods.depositQuote(decimalStr("800")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("200")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp2)), diff --git a/test/LongTailTokenlMode.test.ts b/test/LongTailTokenlMode.test.ts index cc2d19d..152b6dc 100644 --- a/test/LongTailTokenlMode.test.ts +++ b/test/LongTailTokenlMode.test.ts @@ -55,36 +55,36 @@ describe("Trader", () => { it("price discover", async () => { // 10% depth // avg price = 11.137 - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("1000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9988900000000000000000000") // 20% depth // avg price = 12.475 - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("2000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9975049999999999999970000") // 50% depth // avg price = 19.9 - await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("5000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9900499999999999999970000") // 80% depth // avg price = 49.6 - await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9603199999999999999970000") }) it("user has no pnl if buy and sell immediately", async () => { // lp buy - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(lp)) // trader buy and sell - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("1000"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("1000"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) // no profit or loss (may have precision problems) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "0") diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts index b85a8ab..2373ec7 100644 --- a/test/StableCoinMode.test.ts +++ b/test/StableCoinMode.test.ts @@ -54,17 +54,17 @@ describe("Trader", () => { describe("Trade stable coin", () => { it("trade with tiny slippage", async () => { // 10% depth avg price 1.000100000111135 - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("1001")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("1001"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8999899999888865431655") // 99.9% depth avg price 1.00010109 - await ctx.DODO.methods.buyBaseToken(decimalStr("8990"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("8990"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19990")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8990031967806921648") // sell to 99.9% depth avg price 0.9999 - await ctx.DODO.methods.sellBaseToken(decimalStr("19980"), decimalStr("19970")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("19980"), decimalStr("19970"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19986992950440794518402") }) @@ -73,7 +73,7 @@ describe("Trader", () => { // trader could sell any number of base token // but the price will drop quickly await ctx.mintTestToken(trader, decimalStr("10000"), decimalStr("0")) - await ctx.DODO.methods.sellBaseToken(decimalStr("20000"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("20000"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("0")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19998999990001000029997") @@ -82,19 +82,19 @@ describe("Trader", () => { it("huge buy trading amount", async () => { // could not buy all base balance await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("10000"), decimalStr("10010")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("10000"), decimalStr("10010"), "0x").send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ ) // when buy amount close to base balance, price will increase quickly await ctx.mintTestToken(trader, decimalStr("0"), decimalStr("10000")) - await ctx.DODO.methods.buyBaseToken(decimalStr("9999"), decimalStr("20000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9999"), decimalStr("20000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19999")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9000000119999999900000") }) it("tiny withdraw penalty", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("9990"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9990"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) // penalty only 0.2% even if withdraw make pool utilization rate raise to 99.5% assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "9981967500000000") diff --git a/test/Trader.test.ts b/test/Trader.test.ts index ae3b759..9046248 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -24,8 +24,8 @@ async function init(ctx: DODOContext): Promise { await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")) await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")) - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositBaseTo(lp, decimalStr("10")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositQuoteTo(lp, decimalStr("1000")).send(ctx.sendParam(lp)) } describe("Trader", () => { @@ -48,7 +48,7 @@ describe("Trader", () => { describe("R goes above ONE", () => { it("buy when R equals ONE", async () => { - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)), "buy base token when balanced") + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)), "buy base token when balanced") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") @@ -63,8 +63,8 @@ describe("Trader", () => { }) it("buy when R is ABOVE ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130")).send(ctx.sendParam(trader)), "buy when R is ABOVE ONE") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x").send(ctx.sendParam(trader)), "buy when R is ABOVE ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("12")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "794367183433412077653") @@ -77,8 +77,8 @@ describe("Trader", () => { }) it("sell when R is ABOVE ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10.5")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "949280846351657143136") @@ -91,8 +91,8 @@ describe("Trader", () => { }) it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus back to ONE") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus back to ONE") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // trader balances @@ -110,8 +110,8 @@ describe("Trader", () => { }) it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") // trader balances @@ -131,7 +131,7 @@ describe("Trader", () => { describe("R goes below ONE", () => { it("sell when R equals ONE", async () => { - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token when balanced") + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell base token when balanced") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630663") @@ -146,8 +146,8 @@ describe("Trader", () => { }) it("sell when R is BELOW ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is BELOW ONE") + await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is BELOW ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("4")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1535961012052716726151") @@ -160,8 +160,8 @@ describe("Trader", () => { }) it("buy when R is BELOW ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE") + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9.5")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1049294316148665165453") @@ -174,8 +174,8 @@ describe("Trader", () => { }) it("buy when R is BELOW ONE and RStatus back to ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus back to ONE") + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus back to ONE") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // trader balances @@ -193,8 +193,8 @@ describe("Trader", () => { }) it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") // trader balances @@ -214,36 +214,36 @@ describe("Trader", () => { describe("Corner cases", () => { it("buy or sell 0", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("0"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("0"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) - await ctx.DODO.methods.buyBaseToken(decimalStr("0"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("0"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) }) it("buy or sell a tiny amount", async () => { // no precision problem - await ctx.DODO.methods.sellBaseToken("1", decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken("1", decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9999999999999999999") assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") // have precision problem, charge 0 - await ctx.DODO.methods.buyBaseToken("1", decimalStr("1")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken("1", decimalStr("1"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000000") assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // no precision problem if trading amount is extremely small - await ctx.DODO.methods.buyBaseToken("10", decimalStr("1")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken("10", decimalStr("1"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000010") assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999999999999999999100") }) it("sell a huge amount of base token", async () => { await ctx.mintTestToken(trader, decimalStr("10000"), "0") - await ctx.DODO.methods.sellBaseToken(decimalStr("10000"), "0").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10000"), "0", "0x").send(ctx.sendParam(trader)) // nearly drain out quote pool // because the fee donated is greater than remaining quote pool // quote lp earn a considerable profit @@ -255,25 +255,25 @@ describe("Trader", () => { describe("Revert cases", () => { it("price limit", async () => { await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("100")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("100"), "0x").send(ctx.sendParam(trader)), /BUY_BASE_COST_TOO_MUCH/ ) await assert.rejects( - ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("100")).send(ctx.sendParam(trader)), + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("100"), "0x").send(ctx.sendParam(trader)), /SELL_BASE_RECEIVE_NOT_ENOUGH/ ) }) it("base balance limit", async () => { await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ ) - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ ) }) diff --git a/test/UniswapArbitrageur.test.ts b/test/UniswapArbitrageur.test.ts new file mode 100644 index 0000000..b7c53c8 --- /dev/null +++ b/test/UniswapArbitrageur.test.ts @@ -0,0 +1,120 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr } from './utils/Converter'; +import { logGas } from './utils/Log'; +import * as assert from "assert" +import { newContract, UNISWAP_CONTRACT_NAME, UNISWAP_ARBITRAGEUR_CONTRACT_NAME } from './utils/Contracts'; +import { Contract } from 'web3-eth-contract'; + +let lp: string +let keeper: string + +let Uniswap: Contract +let UniswapArbitrageur: Contract + +let UniswapReverse: Contract +let UniswapArbitrageurReverse: Contract + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")) + + lp = ctx.spareAccounts[0] + keeper = ctx.spareAccounts[1] + await ctx.approveDODO(lp) + + await ctx.mintTestToken(lp, decimalStr("100"), decimalStr("10000")) + + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) + + Uniswap = await newContract(UNISWAP_CONTRACT_NAME) + Uniswap.methods.initialize(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + ctx.BASE.methods.transfer(Uniswap.options.address, decimalStr("10")).send(ctx.sendParam(lp)) + ctx.QUOTE.methods.transfer(Uniswap.options.address, decimalStr("2000")).send(ctx.sendParam(lp)) + Uniswap.methods.sync().send(ctx.sendParam(lp)) + + UniswapArbitrageur = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [Uniswap.options.address, ctx.DODO.options.address]) + + UniswapReverse = await newContract(UNISWAP_CONTRACT_NAME) + UniswapReverse.methods.initialize(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + ctx.BASE.methods.transfer(UniswapReverse.options.address, decimalStr("10")).send(ctx.sendParam(lp)) + ctx.QUOTE.methods.transfer(UniswapReverse.options.address, decimalStr("2000")).send(ctx.sendParam(lp)) + UniswapReverse.methods.sync().send(ctx.sendParam(lp)) + + UniswapArbitrageurReverse = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [UniswapReverse.options.address, ctx.DODO.options.address]) +} + +describe("Uniswap Arbitrageur", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("arbitrage with not reverse pair", () => { + it("buy at dodo", async () => { + await ctx.setOraclePrice(decimalStr("100")) + // dodo price 100 uniswap price 200 + // buy at dodo + logGas(await UniswapArbitrageur.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage buy at dodo not reverse") + assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") + }) + + it("sell at dodo", async () => { + await ctx.setOraclePrice(decimalStr("300")) + // dodo price 300 uniswap price 200 + // sell at dodo + logGas(await UniswapArbitrageur.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage sell at dodo not reverse") + assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") + }) + }) + + describe("arbitrage with reverse pair", () => { + it("buy at dodo", async () => { + await ctx.setOraclePrice(decimalStr("100")) + // dodo price 100 uniswap price 200 + // buy at dodo + logGas(await UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage buy at dodo reverse") + assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") + }) + + it("sell at dodo", async () => { + await ctx.setOraclePrice(decimalStr("300")) + // dodo price 300 uniswap price 200 + // sell at dodo + logGas(await UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage sell at dodo reverse") + assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") + }) + }) + + describe("revert cases", () => { + it("price not match", async () => { + await ctx.setOraclePrice(decimalStr("200")) + await assert.rejects( + UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), + /NOT_PROFITABLE/ + ) + await assert.rejects( + UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), + /NOT_PROFITABLE/ + ) + }) + }) +}) \ No newline at end of file diff --git a/test/utils/Context.ts b/test/utils/Context.ts index d50f03c..451bd44 100644 --- a/test/utils/Context.ts +++ b/test/utils/Context.ts @@ -65,7 +65,8 @@ export class DODOContext { async init(config: DODOContextInitConfig) { this.EVM = new EVM this.Web3 = getDefaultWeb3() - this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME) + var cloneFactory = await contracts.newContract(contracts.CLONE_FACTORY_CONTRACT_NAME) + this.BASE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestBase", 18]) this.QUOTE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestQuote", 18]) this.ORACLE = await contracts.newContract(contracts.NAIVE_ORACLE_CONTRACT_NAME) @@ -76,8 +77,10 @@ export class DODOContext { this.Maintainer = allAccounts[2] this.spareAccounts = allAccounts.slice(3, 10) + var DODOTemplate = await contracts.newContract(contracts.DODO_CONTRACT_NAME) + this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME, [DODOTemplate.options.address, cloneFactory.options.address, this.Supervisor]) + await this.DODOZoo.methods.breedDODO( - this.Supervisor, this.Maintainer, this.BASE.options.address, this.QUOTE.options.address, @@ -93,8 +96,6 @@ export class DODOContext { this.BaseCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._BASE_CAPITAL_TOKEN_().call()) this.QuoteCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) - this.DODO.methods.claimOwnership().send(this.sendParam(this.Deployer)) - console.log(log.blueText("[Init dodo context]")) } diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index 31a936c..b07b068 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -10,6 +10,7 @@ if (process.env["COVERAGE"]) { jsonPath = "../../.coverage_artifacts/contracts/" } +const CloneFactory = require(`${jsonPath}CloneFactory.json`) const DODO = require(`${jsonPath}DODO.json`) const DODOZoo = require(`${jsonPath}DODOZoo.json`) const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) @@ -17,10 +18,13 @@ const WETH = require(`${jsonPath}WETH9.json`) const TestERC20 = require(`${jsonPath}TestERC20.json`) const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) +const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) +const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) import { getDefaultWeb3 } from './EVM'; import { Contract } from 'web3-eth-contract'; +export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" export const DODO_CONTRACT_NAME = "DODO" export const TEST_ERC20_CONTRACT_NAME = "TestERC20" export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" @@ -28,6 +32,20 @@ export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" export const WETH_CONTRACT_NAME = "WETH" +export const UNISWAP_CONTRACT_NAME = "Uniswap" +export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" + +var contractMap: { [name: string]: any } = {} +contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory +contractMap[DODO_CONTRACT_NAME] = DODO +contractMap[TEST_ERC20_CONTRACT_NAME] = TestERC20 +contractMap[NAIVE_ORACLE_CONTRACT_NAME] = NaiveOracle +contractMap[DODO_LP_TOKEN_CONTRACT_NAME] = DODOLpToken +contractMap[DODO_ZOO_CONTRACT_NAME] = DODOZoo +contractMap[DODO_ETH_PROXY_CONTRACT_NAME] = DODOEthProxy +contractMap[WETH_CONTRACT_NAME] = WETH +contractMap[UNISWAP_CONTRACT_NAME] = Uniswap +contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur interface ContractJson { abi: any; @@ -36,51 +54,11 @@ interface ContractJson { } export function getContractJSON(contractName: string): ContractJson { - switch (contractName) { - case DODO_CONTRACT_NAME: - return { - abi: DODO.abi, - networks: DODO.networks, - byteCode: DODO.bytecode - }; - case TEST_ERC20_CONTRACT_NAME: - return { - abi: TestERC20.abi, - networks: TestERC20.networks, - byteCode: TestERC20.bytecode - }; - case NAIVE_ORACLE_CONTRACT_NAME: - return { - abi: NaiveOracle.abi, - networks: NaiveOracle.networks, - byteCode: NaiveOracle.bytecode - }; - case DODO_LP_TOKEN_CONTRACT_NAME: - return { - abi: DODOLpToken.abi, - networks: DODOLpToken.networks, - byteCode: DODOLpToken.bytecode - }; - case DODO_ZOO_CONTRACT_NAME: - return { - abi: DODOZoo.abi, - networks: DODOZoo.networks, - byteCode: DODOZoo.bytecode - }; - case DODO_ETH_PROXY_CONTRACT_NAME: - return { - abi: DODOEthProxy.abi, - networks: DODOEthProxy.networks, - byteCode: DODOEthProxy.bytecode - }; - case WETH_CONTRACT_NAME: - return { - abi: WETH.abi, - networks: WETH.networks, - byteCode: WETH.bytecode - }; - default: - throw "CONTRACT_NAME_NOT_FOUND"; + var info = contractMap[contractName] + return { + abi: info.abi, + networks: info.networks, + byteCode: info.bytecode } }