flash loan test
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user