From 61479dbf0430c45317b3ffc5a7618a4bea975027 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 26 Nov 2020 13:22:22 +0800 Subject: [PATCH] DPP trade test --- contracts/DODOPrivatePool/impl/DPP.sol | 2 - contracts/DODOPrivatePool/impl/DPPStorage.sol | 6 - contracts/DODOPrivatePool/impl/DPPVault.sol | 6 +- contracts/lib/PMMPricing.sol | 5 +- test/DPP/trader.test.ts | 195 ++++++++++++++++++ test/utils/DPPContext.ts | 26 ++- 6 files changed, 223 insertions(+), 17 deletions(-) create mode 100644 test/DPP/trader.test.ts diff --git a/contracts/DODOPrivatePool/impl/DPP.sol b/contracts/DODOPrivatePool/impl/DPP.sol index 7a28f1e..32ceda3 100644 --- a/contracts/DODOPrivatePool/impl/DPP.sol +++ b/contracts/DODOPrivatePool/impl/DPP.sol @@ -25,7 +25,6 @@ contract DPP is DPPTrader { address kSource, address iSource, address gasPriceSource, - address dodoSmartApprove, address tradePermissionManager ) external { initOwner(owner); @@ -38,7 +37,6 @@ contract DPP is DPPTrader { _K_ = IExternalValue(kSource); _GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource); _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); - _DODO_SMART_APPROVE_ = dodoSmartApprove; _resetTargetAndReserve(); } diff --git a/contracts/DODOPrivatePool/impl/DPPStorage.sol b/contracts/DODOPrivatePool/impl/DPPStorage.sol index 4d7c976..b9f0f8a 100644 --- a/contracts/DODOPrivatePool/impl/DPPStorage.sol +++ b/contracts/DODOPrivatePool/impl/DPPStorage.sol @@ -27,8 +27,6 @@ import {PMMPricing} from "../../lib/PMMPricing.sol"; contract DPPStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; - address public _DODO_SMART_APPROVE_; - // ============ Variables for Control ============ IExternalValue public _GAS_PRICE_LIMIT_; @@ -78,10 +76,6 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard { _MAINTAINER_ = newMaintainer; } - function setOperator(address newOperator) external onlyOwner { - _OPERATOR_ = newOperator; - } - function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner { _GAS_PRICE_LIMIT_ = IExternalValue(newGasPriceLimitSource); } diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol index a70ef3d..86676b3 100644 --- a/contracts/DODOPrivatePool/impl/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -64,7 +64,7 @@ contract DPPVault is DPPStorage { } function reset( - address from, + address assetTo, uint256 newLpFeeRate, uint256 newMtFeeRate, uint256 newI, @@ -73,8 +73,8 @@ contract DPPVault is DPPStorage { uint256 quoteOutAmount ) public onlyOwner { require(newK > 0 && newK <= 10**18, "K OUT OF RANGE!"); - if (baseOutAmount > 0) _transferBaseOut(from, baseOutAmount); - if (quoteOutAmount > 0) _transferQuoteOut(from, quoteOutAmount); + _transferBaseOut(assetTo, baseOutAmount); + _transferQuoteOut(assetTo, quoteOutAmount); _resetTargetAndReserve(); _LP_FEE_RATE_MODEL_.setFeeRate(newLpFeeRate); _MT_FEE_RATE_MODEL_.setFeeRate(newMtFeeRate); diff --git a/contracts/lib/PMMPricing.sol b/contracts/lib/PMMPricing.sol index 7e274b8..82039fb 100644 --- a/contracts/lib/PMMPricing.sol +++ b/contracts/lib/PMMPricing.sol @@ -213,18 +213,17 @@ library PMMPricing { // ============ Helper functions ============ - // todo 我不确定这个函数是不是能改state的状态 function adjustedTarget(PMMState memory state) internal pure { if (state.R == RState.BELOW_ONE) { state.Q0 = DODOMath._SolveQuadraticFunctionForTarget( - state.B, + state.Q, state.B.sub(state.B0), state.i, state.K ); } else if (state.R == RState.ABOVE_ONE) { state.B0 = DODOMath._SolveQuadraticFunctionForTarget( - state.Q, + state.B, state.Q.sub(state.Q0), DecimalMath.reciprocalFloor(state.i), state.K diff --git a/test/DPP/trader.test.ts b/test/DPP/trader.test.ts new file mode 100644 index 0000000..b52a470 --- /dev/null +++ b/test/DPP/trader.test.ts @@ -0,0 +1,195 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// import * as assert from 'assert'; + +import { decimalStr, gweiStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { DPPContext, getDPPContext } from '../utils/DPPContext'; +import { assert } from 'chai'; +import { EXTERNAL_VALUE_NAME, getContractWithAddress } from '../utils/Contracts'; +const truffleAssert = require('truffle-assertions'); + +let lp: string; +let trader: string; + +async function init(ctx: DPPContext): Promise { + lp = ctx.Deployer + trader = ctx.SpareAccounts[1]; + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + + await ctx.transferBaseToDPP(lp, decimalStr("10")) + await ctx.transferQuoteToDPP(lp, decimalStr("1000")) + await ctx.DPP.methods.reset(lp, decimalStr("0.002"), decimalStr("0.001"), decimalStr("100"), decimalStr("0.1"), "0", "0").send(ctx.sendParam(ctx.Deployer)) + + console.log("deposit") +} + +describe("DPP Trader", () => { + let snapshotId: string; + let ctx: DPPContext; + + before(async () => { + ctx = await getDPPContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("trade", () => { + // it.only("basic check", async () => { + // console.log(await ctx.DPP.methods.getVaultReserve().call()) + // console.log(await ctx.DPP.methods.getPMMState().call()) + // console.log(await ctx.DPP.methods.getMidPrice().call()) + // console.log(await ctx.DPP.methods.querySellQuote(ctx.Deployer, decimalStr("200")).call()) + // console.log(ctx.BASE.options.address) + // console.log(await ctx.DPP.methods._BASE_TOKEN_().call()) + // console.log(ctx.QUOTE.options.address) + // console.log(await ctx.DPP.methods._QUOTE_TOKEN_().call()) + // }) + + // it.only("mannually buy", async () => { + // await ctx.QUOTE.methods.transfer(ctx.DPP.options.address, decimalStr("100")).send(ctx.sendParam(lp)) + // console.log(await ctx.DPP.methods.getQuoteInput().call()) + // console.log(await ctx.DPP.methods.querySellQuote(lp, decimalStr("100")).call()) + // await ctx.DPP.methods.sellQuote(lp).send(ctx.sendParam(lp)) + // }) + + it("first buy and then sell", async () => { + // buy at R=1 + await ctx.transferQuoteToDPP(trader, decimalStr("100")) + await ctx.DPP.methods.sellQuote(trader).send(ctx.sendParam(trader)) + var balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, "10986174542266106306") + assert.equal(balances.traderQuote, decimalStr("900")) + assert.equal(balances.DPPBase, "9012836315765723075") + assert.equal(balances.DPPQuote, decimalStr("1100")) + assert.equal(balances.maintainerBase, "989141968170619") + assert.equal(balances.maintainerQuote, "0") + + // buy at R>1 + await ctx.transferQuoteToDPP(trader, decimalStr("100")) + await ctx.DPP.methods.sellQuote(trader).send(ctx.sendParam(trader)) + balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, "11946772292527553371") + assert.equal(balances.traderQuote, decimalStr("800")) + assert.equal(balances.DPPBase, "8051275077289369844") + assert.equal(balances.DPPQuote, decimalStr("1200")) + assert.equal(balances.maintainerBase, "1952630183076785") + assert.equal(balances.maintainerQuote, "0") + + // sell at R>1 and R not change state + await ctx.transferBaseToDPP(trader, decimalStr("1")) + await ctx.DPP.methods.sellBase(trader).send(ctx.sendParam(trader)) + balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, "10946772292527553371") + assert.equal(balances.traderQuote, "903421814651005338948") + assert.equal(balances.DPPBase, "9051275077289369844") + assert.equal(balances.DPPQuote, "1096474452335302579468") + assert.equal(balances.maintainerBase, "1952630183076785") + assert.equal(balances.maintainerQuote, "103733013692081584") + + // sell at R>1 and R change state + await ctx.transferBaseToDPP(trader, decimalStr("2")) + await ctx.DPP.methods.sellBase(trader).send(ctx.sendParam(trader)) + balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, "8946772292527553371") + assert.equal(balances.traderQuote, "1102638273848343281091") + assert.equal(balances.DPPBase, "11051275077289369844") + assert.equal(balances.DPPQuote, "897058177231046545106") + assert.equal(balances.maintainerBase, "1952630183076785") + assert.equal(balances.maintainerQuote, "303548920610173803") + + var PMMStat = await ctx.DPP.methods.getPMMState().call() + assert.equal(PMMStat.R, "2") + assert.equal(PMMStat.B0, "10005950249348099200") + }); + + it.only("first sell and then buy", async () => { + // sell at R=1 + await ctx.transferBaseToDPP(trader, decimalStr("1")) + await ctx.DPP.methods.sellBase(trader).send(ctx.sendParam(trader)) + var balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, decimalStr("9")) + assert.equal(balances.traderQuote, "1098617454226610630662") + assert.equal(balances.DPPBase, decimalStr("11")) + assert.equal(balances.DPPQuote, "901283631576572307521") + assert.equal(balances.maintainerBase, "0") + assert.equal(balances.maintainerQuote, "98914196817061817") + + // buy at R>1 + await ctx.transferBaseToDPP(trader, decimalStr("1")) + await ctx.DPP.methods.sellBase(trader).send(ctx.sendParam(trader)) + balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, decimalStr("8")) + assert.equal(balances.traderQuote, "1194677229252755337107") + assert.equal(balances.DPPBase, decimalStr("12")) + assert.equal(balances.DPPQuote, "805127507728936984519") + assert.equal(balances.maintainerBase, "0") + assert.equal(balances.maintainerQuote, "195263018307678374") + + // sell at R>1 and R not change state + await ctx.transferQuoteToDPP(trader, decimalStr("100")) + await ctx.DPP.methods.sellQuote(trader).send(ctx.sendParam(trader)) + balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, "9034218146510053389") + assert.equal(balances.traderQuote, "1094677229252755337107") + assert.equal(balances.DPPBase, "10964744523353025795") + assert.equal(balances.DPPQuote, "905127507728936984519") + assert.equal(balances.maintainerBase, "1037330136920816") + assert.equal(balances.maintainerQuote, "195263018307678374") + + // sell at R>1 and R change state + await ctx.transferQuoteToDPP(trader, decimalStr("200")) + await ctx.DPP.methods.sellQuote(trader).send(ctx.sendParam(trader)) + balances = await ctx.getBalances(trader) + + assert.equal(balances.traderBase, "11026382738483432810") + assert.equal(balances.traderQuote, "894677229252755337107") + assert.equal(balances.DPPBase, "8970581772310465451") + assert.equal(balances.DPPQuote, "1105127507728936984519") + assert.equal(balances.maintainerBase, "3035489206101739") + assert.equal(balances.maintainerQuote, "195263018307678374") + + var PMMStat = await ctx.DPP.methods.getPMMState().call() + + assert.equal(PMMStat.R, "1") + assert.equal(PMMStat.Q0, "1000595024934809920179") + }); + + + it("flash loan", async () => { + + }) + + it("revert cases", async () => { + var gasPriceLimitContract = getContractWithAddress(EXTERNAL_VALUE_NAME, await ctx.DPP.methods._GAS_PRICE_LIMIT_().call()) + await gasPriceLimitContract.methods.set(gweiStr("10")).send(ctx.sendParam(ctx.Deployer)) + + + await truffleAssert.reverts( + ctx.DPP.methods.sellQuote(trader).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), "GAS_PRICE_EXCEED" + ) + + }) + }); +}); \ No newline at end of file diff --git a/test/utils/DPPContext.ts b/test/utils/DPPContext.ts index 74022fa..d8366fc 100644 --- a/test/utils/DPPContext.ts +++ b/test/utils/DPPContext.ts @@ -19,6 +19,15 @@ BigNumber.config({ DECIMAL_PLACES: 80, }); +export interface DPPContextBalances { + traderBase: string, + traderQuote: string, + DPPBase: string, + DPPQuote: string, + maintainerBase: string, + maintainerQuote: string +} + export interface DPPContextInitConfig { lpFeeRate: string; mtFeeRate: string; @@ -69,7 +78,6 @@ export class DPPContext { var gasPriceSource = await contracts.newContract(contracts.EXTERNAL_VALUE_NAME) var iSource = await contracts.newContract(contracts.EXTERNAL_VALUE_NAME) var kSource = await contracts.newContract(contracts.EXTERNAL_VALUE_NAME) - this.BASE = await contracts.newContract( contracts.MINTABLE_ERC20_CONTRACT_NAME, ["TestBase", "BASE", 18] @@ -87,7 +95,6 @@ export class DPPContext { await this.DPP.methods.init( this.Deployer, this.Maintainer, - this.Deployer, this.BASE.options.address, this.QUOTE.options.address, lpFeeRateModel.options.address, @@ -98,9 +105,10 @@ export class DPPContext { permissionManager.options.address, ).send(this.sendParam(this.Deployer)) - await gasPriceSource.methods.init(this.DPP.options.address, MAX_UINT256).send(this.sendParam(this.Deployer)) + await gasPriceSource.methods.init(this.Deployer, MAX_UINT256).send(this.sendParam(this.Deployer)) await lpFeeRateModel.methods.init(this.DPP.options.address, config.lpFeeRate).send(this.sendParam(this.Deployer)) await mtFeeRateModel.methods.init(this.DPP.options.address, config.mtFeeRate).send(this.sendParam(this.Deployer)) + await kSource.methods.init(this.DPP.options.address, config.k).send(this.sendParam(this.Deployer)) await iSource.methods.init(this.DPP.options.address, config.i).send(this.sendParam(this.Deployer)) @@ -130,6 +138,18 @@ export class DPPContext { async transferQuoteToDPP(account: string, amount: string) { await this.QUOTE.methods.transfer(this.DPP.options.address, amount).send(this.sendParam(account)) } + + async getBalances(trader: string) { + var balances: DPPContextBalances = { + traderBase: await this.BASE.methods.balanceOf(trader).call(), + traderQuote: await this.QUOTE.methods.balanceOf(trader).call(), + DPPBase: await this.BASE.methods.balanceOf(this.DPP.options.address).call(), + DPPQuote: await this.QUOTE.methods.balanceOf(this.DPP.options.address).call(), + maintainerBase: await this.BASE.methods.balanceOf(this.Maintainer).call(), + maintainerQuote: await this.QUOTE.methods.balanceOf(this.Maintainer).call(), + } + return balances + } } export async function getDPPContext(