跳到主要内容

Description

Code

DVM: The DVM contract is designed to set up and manage the basic configurations of a decentralized trading platform, including fee rates, trading parameters, and the TWAP toggle.

DVMFunding: Deal with the shares.

DVMTrader: Deal with the flashloan & Base Tokens.

Goal

Make WETH.balanceOf(dvm) == 0;, Start with 100 ether

Solution

The DVM is a DODO Vending Machine that is designed to sell tokens without large initial liquidity requirements. Beacuse it is cloned, so when i check the init() function, i found that everyone can call the init(), it is external.

contract DVM is DVMTrader, DVMFunding {
function init(
address maintainer,
address baseTokenAddress,
address quoteTokenAddress,
uint256 lpFeeRate,
address mtFeeRateModel,
uint256 i,
uint256 k,
bool isOpenTWAP
) external {
require(baseTokenAddress != quoteTokenAddress, "BASE_QUOTE_CAN_NOT_BE_SAME");
_BASE_TOKEN_ = IERC20(baseTokenAddress);
_QUOTE_TOKEN_ = IERC20(quoteTokenAddress);

require(i > 0 && i <= 10**36);
_I_ = i;

require(k <= 10**18);
_K_ = k;

_LP_FEE_RATE_ = lpFeeRate;
_MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel);
_MAINTAINER_ = maintainer;

_IS_OPEN_TWAP_ = isOpenTWAP;
if(isOpenTWAP) _BLOCK_TIMESTAMP_LAST_ = uint32(block.timestamp % 2**32);

string memory connect = "_";
string memory suffix = "DLP";

name = string(abi.encodePacked(suffix, connect, addressToShortString(address(this))));
symbol = "DLP";
decimals = _BASE_TOKEN_.decimals();

// ============================== Permit ====================================
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
// keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
// ==========================================================================
}

So we can call flashloan, and in our callback function, we can call the init(), change the baseToken and QuoteToken address.

function flashLoan(
uint256 baseAmount,
uint256 quoteAmount,
address assetTo,
bytes calldata data
) external preventReentrant {
_transferBaseOut(assetTo, baseAmount);
_transferQuoteOut(assetTo, quoteAmount);

if (data.length > 0)
IDODOCallee(assetTo).DVMFlashLoanCall(msg.sender, baseAmount, quoteAmount, data);

uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this));
uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this));

// no input -> pure loss
require(
baseBalance >= _BASE_RESERVE_ || quoteBalance >= _QUOTE_RESERVE_,
"FLASH_LOAN_FAILED"
);

// sell quote
if (baseBalance < _BASE_RESERVE_) {
uint256 quoteInput = quoteBalance.sub(uint256(_QUOTE_RESERVE_));
(uint256 receiveBaseAmount, uint256 mtFee) = querySellQuote(tx.origin, quoteInput);
require(uint256(_BASE_RESERVE_).sub(baseBalance) <= receiveBaseAmount, "FLASH_LOAN_FAILED");

_transferBaseOut(_MAINTAINER_, mtFee);
emit DODOSwap(
address(_QUOTE_TOKEN_),
address(_BASE_TOKEN_),
quoteInput,
receiveBaseAmount,
msg.sender,
assetTo
);
}

// sell base
if (quoteBalance < _QUOTE_RESERVE_) {
uint256 baseInput = baseBalance.sub(uint256(_BASE_RESERVE_));
(uint256 receiveQuoteAmount, uint256 mtFee) = querySellBase(tx.origin, baseInput);
require(uint256(_QUOTE_RESERVE_).sub(quoteBalance) <= receiveQuoteAmount, "FLASH_LOAN_FAILED");

_transferQuoteOut(_MAINTAINER_, mtFee);
emit DODOSwap(
address(_BASE_TOKEN_),
address(_QUOTE_TOKEN_),
baseInput,
receiveQuoteAmount,
msg.sender,
assetTo
);
}

_sync();

emit DODOFlashLoan(msg.sender, assetTo, baseAmount, quoteAmount);
}