diff --git a/contracts/DODOPrivatePool/impl/DPPTrader.sol b/contracts/DODOPrivatePool/impl/DPPTrader.sol index ba64c4d..3e3ac0e 100644 --- a/contracts/DODOPrivatePool/impl/DPPTrader.sol +++ b/contracts/DODOPrivatePool/impl/DPPTrader.sol @@ -25,7 +25,10 @@ contract DPPTrader is DPPVault { } modifier isSellAllow(address trader) { - require(!_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader),"TRADER_SELL_NOT_ALLOWED"); + require( + !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), + "TRADER_SELL_NOT_ALLOWED" + ); _; } @@ -75,7 +78,10 @@ contract DPPTrader is DPPVault { uint256 newQuoteTarget; PMMPricing.RState newRState; - (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellQuote(tx.origin,quoteInput); + (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellQuote( + tx.origin, + quoteInput + ); _transferBaseOut(to, receiveBaseAmount); _transferBaseOut(_MAINTAINER_, mtFee); @@ -105,15 +111,15 @@ contract DPPTrader is DPPVault { uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); - // no output -> pure profit - if (baseBalance >= _BASE_RESERVE_ && quoteBalance >= _QUOTE_RESERVE_) return; - // no input -> pure loss require( baseBalance >= _BASE_RESERVE_ || quoteBalance >= _QUOTE_RESERVE_, "FLASH_LOAN_FAILED" ); + // no output -> pure profit + if (baseBalance >= _BASE_RESERVE_ && quoteBalance >= _QUOTE_RESERVE_) return; + // sell quote case // quote input + base output if (baseBalance < _BASE_RESERVE_) { @@ -223,4 +229,9 @@ contract DPPTrader is DPPVault { function getMidPrice() public view returns (uint256 midPrice) { return PMMPricing.getMidPrice(getPMMState()); } + + function _syncReserve() internal { + _BASE_RESERVE_ = _BASE_TOKEN_.balanceOf(address(this)); + _QUOTE_RESERVE_ = _QUOTE_TOKEN_.balanceOf(address(this)); + } } diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol index 471109f..0783ed4 100644 --- a/contracts/DODOPrivatePool/impl/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -51,12 +51,6 @@ contract DPPVault is DPPStorage { _setRState(); } - function _syncReserve() internal { - _BASE_RESERVE_ = _BASE_TOKEN_.balanceOf(address(this)); - _QUOTE_RESERVE_ = _QUOTE_TOKEN_.balanceOf(address(this)); - _setRState(); - } - function _resetTargetAndReserve() internal { _BASE_TARGET_ = _BASE_TOKEN_.balanceOf(address(this)); _QUOTE_TARGET_ = _QUOTE_TOKEN_.balanceOf(address(this)); diff --git a/contracts/DODOVendingMachine/impl/DVMTrader.sol b/contracts/DODOVendingMachine/impl/DVMTrader.sol index 4aac393..18bad0d 100644 --- a/contracts/DODOVendingMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendingMachine/impl/DVMTrader.sol @@ -48,7 +48,7 @@ contract DVMTrader is DVMVault { returns (uint256 receiveQuoteAmount) { uint256 baseInput = getBaseInput(); - require(baseInput > 0, 'INSUFFICIENT_BASE_INPUT'); + require(baseInput > 0, "INSUFFICIENT_BASE_INPUT"); uint256 mtFee; (receiveQuoteAmount, mtFee) = querySellBase(tx.origin, baseInput); _transferQuoteOut(to, receiveQuoteAmount); @@ -65,7 +65,7 @@ contract DVMTrader is DVMVault { returns (uint256 receiveBaseAmount) { uint256 quoteInput = getQuoteInput(); - require(quoteInput > 0, 'INSUFFICIENT_QUOTE_INPUT'); + require(quoteInput > 0, "INSUFFICIENT_QUOTE_INPUT"); uint256 mtFee; (receiveBaseAmount, mtFee) = querySellQuote(tx.origin, quoteInput); _transferBaseOut(to, receiveBaseAmount); @@ -88,33 +88,35 @@ contract DVMTrader is DVMVault { if (data.length > 0) IDODOCallee(assetTo).DVMFlashLoanCall(msg.sender, baseAmount, quoteAmount, data); - (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve(); (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(tx.origin); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(tx.origin); - if (baseBalance < baseReserve) { - uint256 validBaseOut = DecimalMath.divCeil( - baseReserve - baseBalance, - DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) - ); - baseBalance = baseReserve.sub(validBaseOut); - _transferBaseOut(_MAINTAINER_, DecimalMath.mulFloor(validBaseOut, mtFeeRate)); - } - if (quoteBalance < quoteReserve) { - uint256 validQuoteOut = DecimalMath.divCeil( - quoteReserve - quoteBalance, - DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) - ); - quoteBalance = quoteReserve.sub(validQuoteOut); - _transferQuoteOut(_MAINTAINER_, DecimalMath.mulFloor(validQuoteOut, mtFeeRate)); - } - + // no input -> pure loss require( - calculateBase0(baseBalance, quoteBalance) >= calculateBase0(baseReserve, quoteReserve), + baseBalance >= _BASE_RESERVE_ || quoteBalance >= _QUOTE_RESERVE_, "FLASH_LOAN_FAILED" ); + // no output -> pure profit + if (baseBalance >= _BASE_RESERVE_ && quoteBalance >= _QUOTE_RESERVE_) return; + + if (baseBalance < _BASE_RESERVE_) { + (uint256 receiveBaseAmount, uint256 mtFee) = querySellQuote( + tx.origin, + quoteBalance.sub(_QUOTE_RESERVE_) + ); + require(_BASE_RESERVE_.sub(baseBalance) <= receiveBaseAmount, "FLASH_LOAN_FAILED"); + _transferBaseOut(_MAINTAINER_, mtFee); + } + + if (quoteBalance < _QUOTE_RESERVE_) { + (uint256 receiveQuoteAmount, uint256 mtFee) = querySellBase( + tx.origin, + baseBalance.sub(_BASE_RESERVE_) + ); + require(_QUOTE_RESERVE_.sub(quoteBalance) <= receiveQuoteAmount, "FLASH_LOAN_FAILED"); + _transferQuoteOut(_MAINTAINER_, mtFee); + } + _sync(); } diff --git a/test/DPP/trader.test.ts b/test/DPP/trader.test.ts index b52a470..3e181b3 100644 --- a/test/DPP/trader.test.ts +++ b/test/DPP/trader.test.ts @@ -178,7 +178,35 @@ describe("DPP Trader", () => { it("flash loan", async () => { + // buy + await ctx.transferQuoteToDPP(trader, decimalStr("200")) + // buy failed + await truffleAssert.reverts(ctx.DPP.methods.flashLoan("1946763594380080788", "0", trader, "0x").send(ctx.sendParam(trader)), "FLASH_LOAN_FAILED") + + // buy succeed + await ctx.DPP.methods.flashLoan("1946763594380080787", "0", trader, "0x").send(ctx.sendParam(trader)) + + // trader balances + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "11946763594380080787" + ); + + // sell + await ctx.transferBaseToDPP(trader, decimalStr("1")) + + // sell failed + await truffleAssert.reverts(ctx.DPP.methods.flashLoan("0", "103421810640399874604", trader, "0x").send(ctx.sendParam(trader)), "FLASH_LOAN_FAILED") + + // sell succeed + await ctx.DPP.methods.flashLoan("0", "103421810640399874603", trader, "0x").send(ctx.sendParam(trader)) + + // trader balances + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "903421810640399874603" + ); }) it("revert cases", async () => { diff --git a/test/DVM/trader.test.ts b/test/DVM/trader.test.ts index 5381bc1..81de2ce 100644 --- a/test/DVM/trader.test.ts +++ b/test/DVM/trader.test.ts @@ -168,6 +168,35 @@ describe("Trader", () => { }); it("flash loan", async () => { + // buy + await ctx.transferQuoteToDVM(trader, decimalStr("200")) + + // buy failed + await truffleAssert.reverts(ctx.DVM.methods.flashLoan("1946763594380080788", "0", trader, "0x").send(ctx.sendParam(trader)), "FLASH_LOAN_FAILED") + + // buy succeed + await ctx.DVM.methods.flashLoan("1946763594380080787", "0", trader, "0x").send(ctx.sendParam(trader)) + + // trader balances + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "11946763594380080787" + ); + + // sell + await ctx.transferBaseToDVM(trader, decimalStr("1")) + + // sell failed + await truffleAssert.reverts(ctx.DVM.methods.flashLoan("0", "103421810640399874604", trader, "0x").send(ctx.sendParam(trader)), "FLASH_LOAN_FAILED") + + // sell succeed + await ctx.DVM.methods.flashLoan("0", "103421810640399874603", trader, "0x").send(ctx.sendParam(trader)) + + // trader balances + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "903421810640399874603" + ); }) diff --git a/test/IDODOCallee/DODOCallee.test.ts b/test/IDODOCallee/DODOCallee.test.ts deleted file mode 100644 index e69de29..0000000