From d90e031a30429c5b898ca4b3c01cf2088c6b48e6 Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 29 Nov 2020 17:38:13 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E9=81=8D=E8=B5=B0=E6=9F=A5?= =?UTF-8?q?=20snapshot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/DODOPrivatePool/impl/DPPStorage.sol | 48 +++++++---- contracts/DODOPrivatePool/impl/DPPVault.sol | 14 +-- contracts/DODOVendingMachine/impl/DVM.sol | 50 ++++++----- .../DODOVendingMachine/impl/DVMFunding.sol | 42 ++++++--- .../DODOVendingMachine/impl/DVMStorage.sol | 44 ++++++---- .../DODOVendingMachine/impl/DVMTrader.sol | 65 ++++++++++---- .../DODOVendingMachine/impl/DVMVault.sol | 32 ++----- contracts/SmartRoute/DODOV1Proxy01.sol | 10 +-- .../IDODO.sol => SmartRoute/intf/IDODOV1.sol} | 5 +- .../lib}/DODOSellHelper.sol | 24 +++--- .../{helper => external/ERC20}/TestERC20.sol | 8 +- contracts/helper/TestWETH.sol | 77 ----------------- contracts/intf/IVault.sol | 15 ---- contracts/lib/CloneFactory.sol | 17 ---- contracts/lib/PMMPricing.sol | 32 ++++--- test/DVM/funding.test.ts | 30 ++++++- test/DVM/trader.test.ts | 86 +++++++++---------- 17 files changed, 285 insertions(+), 314 deletions(-) rename contracts/{intf/IDODO.sol => SmartRoute/intf/IDODOV1.sol} (99%) rename contracts/{helper => SmartRoute/lib}/DODOSellHelper.sol (90%) rename contracts/{helper => external/ERC20}/TestERC20.sol (92%) delete mode 100644 contracts/helper/TestWETH.sol delete mode 100644 contracts/intf/IVault.sol diff --git a/contracts/DODOPrivatePool/impl/DPPStorage.sol b/contracts/DODOPrivatePool/impl/DPPStorage.sol index 5b5d729..578859c 100644 --- a/contracts/DODOPrivatePool/impl/DPPStorage.sol +++ b/contracts/DODOPrivatePool/impl/DPPStorage.sol @@ -27,20 +27,17 @@ import {PMMPricing} from "../../lib/PMMPricing.sol"; contract DPPStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; - // ============ Variables for Control ============ - - IExternalValue public _GAS_PRICE_LIMIT_; - // ============ Advanced Controls ============ bool public _BUYING_CLOSE_; bool public _SELLING_CLOSE_; IPermissionManager public _TRADE_PERMISSION_; + IExternalValue public _GAS_PRICE_LIMIT_; // ============ Core Address ============ - address public _MAINTAINER_; // collect maintainer fee + address public _MAINTAINER_; IERC20 public _BASE_TOKEN_; IERC20 public _QUOTE_TOKEN_; @@ -58,41 +55,72 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard { IExternalValue public _K_; IExternalValue public _I_; + // ============ Events ============ + + event SetLpFeeRateModel(address indexed oldAddr, address indexed newAddr); + + event SetMtFeeRateModel(address indexed oldAddr, address indexed newAddr); + + event SetTradePermissionManager(address indexed oldAddr, address indexed newAddr); + + event SetMaintainer(address indexed oldAddr, address indexed newAddr); + + event SetGasPriceSource(address indexed oldAddr, address indexed newAddr); + + event SetISource(address indexed oldAddr, address indexed newAddr); + + event SetKSource(address indexed oldAddr, address indexed newAddr); + + event SetBuy(bool allow); + + event SetSell(bool allow); + // ============ Setting Functions ============ function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { + emit SetLpFeeRateModel(address(_LP_FEE_RATE_MODEL_), newLpFeeRateModel); _LP_FEE_RATE_MODEL_ = IFeeRateModel(newLpFeeRateModel); } function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner { + emit SetMtFeeRateModel(address(_MT_FEE_RATE_MODEL_), newMtFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(newMtFeeRateModel); } function setTradePermissionManager(address newTradePermissionManager) external onlyOwner { + emit SetTradePermissionManager(address(_TRADE_PERMISSION_), newTradePermissionManager); _TRADE_PERMISSION_ = IPermissionManager(newTradePermissionManager); } function setMaintainer(address newMaintainer) external onlyOwner { + emit SetMaintainer(address(_MAINTAINER_), newMaintainer); _MAINTAINER_ = newMaintainer; } function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner { + emit SetGasPriceSource(address(_GAS_PRICE_LIMIT_), newGasPriceLimitSource); _GAS_PRICE_LIMIT_ = IExternalValue(newGasPriceLimitSource); } function setISource(address newISource) external onlyOwner { + emit SetISource(address(_I_), newISource); _I_ = IExternalValue(newISource); + _checkIK(); } function setKSource(address newKSource) external onlyOwner { + emit SetKSource(address(_K_), newKSource); _K_ = IExternalValue(newKSource); + _checkIK(); } function setBuy(bool open) external onlyOwner { + emit SetBuy(open); _BUYING_CLOSE_ = !open; } function setSell(bool open) external onlyOwner { + emit SetSell(open); _SELLING_CLOSE_ = !open; } @@ -102,14 +130,4 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard { require(k > 0 && k <= 1e18, "K_OUT_OF_RANGE"); require(i > 0 && i <= 1e36, "I_OUT_OF_RANGE"); } - - // ============ View Functions ============ - - function getLpFeeRate(address trader) external view returns (uint256 feeRate) { - return _LP_FEE_RATE_MODEL_.getFeeRate(trader); - } - - function getMtFeeRate(address trader) external view returns (uint256 feeRate) { - return _MT_FEE_RATE_MODEL_.getFeeRate(trader); - } } diff --git a/contracts/DODOPrivatePool/impl/DPPVault.sol b/contracts/DODOPrivatePool/impl/DPPVault.sol index cb0f760..55735e3 100644 --- a/contracts/DODOPrivatePool/impl/DPPVault.sol +++ b/contracts/DODOPrivatePool/impl/DPPVault.sol @@ -23,13 +23,6 @@ contract DPPVault is DPPStorage { // ============ Get Input ============ - function getInput() public view returns (uint256 baseInput, uint256 quoteInput) { - return ( - _BASE_TOKEN_.balanceOf(address(this)).sub(_BASE_RESERVE_), - _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_) - ); - } - function getBaseInput() public view returns (uint256 input) { return _BASE_TOKEN_.balanceOf(address(this)).sub(_BASE_RESERVE_); } @@ -38,11 +31,6 @@ contract DPPVault is DPPStorage { return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_); } - // ============ Vault Related - function getVaultReserve() public view returns (uint256 baseReserve, uint256 quoteReserve) { - return (_BASE_RESERVE_, _QUOTE_RESERVE_); - } - // ============ Set States ============ function setTarget(uint256 baseTarget, uint256 quoteTarget) public preventReentrant onlyOwner { @@ -90,7 +78,7 @@ contract DPPVault is DPPStorage { } } - // ============ Assets Transfer ============ + // ============ Asset Out ============ function _transferBaseOut(address to, uint256 amount) internal { if (amount > 0) { diff --git a/contracts/DODOVendingMachine/impl/DVM.sol b/contracts/DODOVendingMachine/impl/DVM.sol index 2ec13b9..7ae4b75 100644 --- a/contracts/DODOVendingMachine/impl/DVM.sol +++ b/contracts/DODOVendingMachine/impl/DVM.sol @@ -30,15 +30,10 @@ contract DVM is DVMTrader, DVMFunding { uint256 k ) external { initOwner(owner); + + require(baseTokenAddress != quoteTokenAddress, "BASE_QUOTE_CAN_NOT_BE_SAME"); _BASE_TOKEN_ = IERC20(baseTokenAddress); _QUOTE_TOKEN_ = IERC20(quoteTokenAddress); - _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); - _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); - _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); - _GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource); - _MAINTAINER_ = maintainer; - - require(_BASE_TOKEN_ != _QUOTE_TOKEN_, "BASE_QUOTE_CAN_NOT_BE_SAME"); require(i > 0 && i <= 10**36); _I_ = i; @@ -46,32 +41,35 @@ contract DVM is DVMTrader, DVMFunding { require(k > 0 && k <= 10**18); _K_ = k; + _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); + _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); + _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); + _GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource); + _MAINTAINER_ = maintainer; + string memory connect = "_"; string memory suffix = "DLP"; - uint32 uid = uint32(address(this)); - bytes memory id = new bytes(4); - id[0] = bytes1(uint8(48 + (uid % 10))); - id[1] = bytes1(uint8(48 + ((uid / 10) % 10))); - id[2] = bytes1(uint8(48 + ((uid / 100) % 10))); - id[3] = bytes1(uint8(48 + ((uid / 1000) % 10))); - name = string( - abi.encodePacked( - suffix, - connect, - _BASE_TOKEN_.symbol(), - connect, - _QUOTE_TOKEN_.symbol(), - connect, - string(id) - ) - ); + name = string(abi.encodePacked(suffix, connect, addressToShortString(address(this)))); symbol = "DLP"; decimals = _BASE_TOKEN_.decimals(); } + function addressToShortString(address _addr) public pure returns (string memory) { + bytes32 value = bytes32(uint256(_addr)); + bytes memory alphabet = "0123456789abcdef"; + + bytes memory str = new bytes(8); + for (uint256 i = 0; i < 4; i++) { + str[i * 2] = alphabet[uint8(value[i + 12] >> 4)]; + str[1 + i * 2] = alphabet[uint8(value[i + 12] & 0x0f)]; + } + return string(str); + } + // ============ Version Control ============ - function version() external pure returns (uint256) { - return 100; // 1.0.0 + + function version() external pure returns (string memory) { + return "DVM 1.0.0"; } } diff --git a/contracts/DODOVendingMachine/impl/DVMFunding.sol b/contracts/DODOVendingMachine/impl/DVMFunding.sol index d04b14f..305bc3a 100644 --- a/contracts/DODOVendingMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendingMachine/impl/DVMFunding.sol @@ -13,27 +13,39 @@ import {DecimalMath} from "../../lib/DecimalMath.sol"; import {IDODOCallee} from "../../intf/IDODOCallee.sol"; contract DVMFunding is DVMVault { - // shares [round down] + // ============ Events ============ + + event BuyShares(address indexed user, uint256 increaseShares, uint256 totalShares); + + event SellShares(address indexed user, uint256 decreaseShares, uint256 totalShares); + + // ============ Buy & Sell Shares ============ + + // buy shares [round down] function buyShares(address to) external preventReentrant returns ( uint256 shares, - uint256 baseAmount, - uint256 quoteAmount + uint256 baseInput, + uint256 quoteInput ) { - uint256 baseInput = getBaseInput(); - uint256 quoteInput = getQuoteInput(); - require(baseInput > 0, "NO_BASE_INPUT"); + uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); + uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); uint256 baseReserve = _BASE_RESERVE_; uint256 quoteReserve = _QUOTE_RESERVE_; + + baseInput = baseBalance.sub(baseReserve); + quoteInput = quoteBalance.sub(quoteReserve); + require(baseInput > 0, "NO_BASE_INPUT"); + // case 1. initial supply // 包含了 baseReserve == 0 && quoteReserve == 0 的情况 // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 // 但有可能出现,reserve>0但totalSupply=0的场景 if (totalSupply == 0) { - shares = getBaseBalance(); // 以免出现balance很大但shares很小的情况 + shares = baseBalance; // 以免出现balance很大但shares很小的情况 } else if (baseReserve > 0 && quoteReserve == 0) { // case 2. supply when quote reserve is 0 shares = baseInput.mul(totalSupply).div(baseReserve); @@ -46,10 +58,10 @@ contract DVMFunding is DVMVault { } _mint(to, shares); _sync(); - return (shares, baseInput, quoteInput); + emit BuyShares(to, shares, _SHARES_[to]); } - // withdraw amount [round down] + // sell shares [round down] function sellShares( uint256 shareAmount, address to, @@ -57,12 +69,20 @@ contract DVMFunding is DVMVault { uint256 quoteMinAmount, bytes calldata data ) external preventReentrant returns (uint256 baseAmount, uint256 quoteAmount) { - (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); + uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); + uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); uint256 totalShares = totalSupply; + require(shareAmount <= _SHARES_[msg.sender], "DLP_NOT_ENOUGH"); + baseAmount = baseBalance.mul(shareAmount).div(totalShares); quoteAmount = quoteBalance.mul(shareAmount).div(totalShares); - require(baseAmount >= baseMinAmount && quoteAmount >= quoteMinAmount,'WITHDRAW_DLP_NOT_ENOUGH'); + + require( + baseAmount >= baseMinAmount && quoteAmount >= quoteMinAmount, + "WITHDRAW_NOT_ENOUGH" + ); + _burn(msg.sender, shareAmount); _transferBaseOut(to, baseAmount); _transferQuoteOut(to, quoteAmount); diff --git a/contracts/DODOVendingMachine/impl/DVMStorage.sol b/contracts/DODOVendingMachine/impl/DVMStorage.sol index c3be8e9..09dd951 100644 --- a/contracts/DODOVendingMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendingMachine/impl/DVMStorage.sol @@ -21,20 +21,17 @@ import {IERC20} from "../../intf/IERC20.sol"; contract DVMStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; - // ============ Variables for Control ============ - - IExternalValue public _GAS_PRICE_LIMIT_; - // ============ Advanced Controls ============ bool public _BUYING_CLOSE_; bool public _SELLING_CLOSE_; IPermissionManager public _TRADE_PERMISSION_; + IExternalValue public _GAS_PRICE_LIMIT_; // ============ Core Address ============ - address public _MAINTAINER_; // collect maintainer fee + address public _MAINTAINER_; IERC20 public _BASE_TOKEN_; IERC20 public _QUOTE_TOKEN_; @@ -42,7 +39,7 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { uint256 public _BASE_RESERVE_; uint256 public _QUOTE_RESERVE_; - // ============ Shares ============ + // ============ Shares (ERC20) ============ string public symbol; uint256 public decimals; @@ -59,43 +56,56 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { uint256 public _K_; uint256 public _I_; + // ============ Events ============ + + event SetLpFeeRateModel(address indexed oldAddr, address indexed newAddr); + + event SetMtFeeRateModel(address indexed oldAddr, address indexed newAddr); + + event SetTradePermissionManager(address indexed oldAddr, address indexed newAddr); + + event SetMaintainer(address indexed oldAddr, address indexed newAddr); + + event SetGasPriceSource(address indexed oldAddr, address indexed newAddr); + + event SetBuy(bool allow); + + event SetSell(bool allow); + // ============ Setting Functions ============ + function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { + emit SetLpFeeRateModel(address(_LP_FEE_RATE_MODEL_), newLpFeeRateModel); _LP_FEE_RATE_MODEL_ = IFeeRateModel(newLpFeeRateModel); } function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner { + emit SetMtFeeRateModel(address(_MT_FEE_RATE_MODEL_), newMtFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(newMtFeeRateModel); } function setTradePermissionManager(address newTradePermissionManager) external onlyOwner { + emit SetTradePermissionManager(address(_TRADE_PERMISSION_), newTradePermissionManager); _TRADE_PERMISSION_ = IPermissionManager(newTradePermissionManager); } function setMaintainer(address newMaintainer) external onlyOwner { + emit SetMaintainer(address(_MAINTAINER_), newMaintainer); _MAINTAINER_ = newMaintainer; } function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner { + emit SetGasPriceSource(address(_GAS_PRICE_LIMIT_), newGasPriceLimitSource); _GAS_PRICE_LIMIT_ = IExternalValue(newGasPriceLimitSource); } function setBuy(bool open) external onlyOwner { + emit SetBuy(open); _BUYING_CLOSE_ = !open; } function setSell(bool open) external onlyOwner { + emit SetSell(open); _SELLING_CLOSE_ = !open; } - - // ============ View Functions ============ - - function getLpFeeRate(address trader) external view returns (uint256 feeRate) { - return _LP_FEE_RATE_MODEL_.getFeeRate(trader); - } - - function getMtFeeRate(address trader) external view returns (uint256 feeRate) { - return _MT_FEE_RATE_MODEL_.getFeeRate(trader); - } - } diff --git a/contracts/DODOVendingMachine/impl/DVMTrader.sol b/contracts/DODOVendingMachine/impl/DVMTrader.sol index d3c2449..6c2404d 100644 --- a/contracts/DODOVendingMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendingMachine/impl/DVMTrader.sol @@ -18,6 +18,16 @@ import {PMMPricing} from "../../lib/PMMPricing.sol"; contract DVMTrader is DVMVault { using SafeMath for uint256; + // ============ Events ============ + + event DVMSwap( + address indexed fromToken, + address indexed toToken, + uint256 fromAmount, + uint256 toAmount, + address trader + ); + // ============ Modifiers ============ modifier isBuyAllow(address trader) { @@ -53,7 +63,13 @@ contract DVMTrader is DVMVault { _transferQuoteOut(to, receiveQuoteAmount); _transferQuoteOut(_MAINTAINER_, mtFee); _sync(); - return receiveQuoteAmount; + emit DVMSwap( + address(_BASE_TOKEN_), + address(_QUOTE_TOKEN_), + baseInput, + receiveQuoteAmount, + tx.origin + ); } function sellQuote(address to) @@ -69,7 +85,13 @@ contract DVMTrader is DVMVault { _transferBaseOut(to, receiveBaseAmount); _transferBaseOut(_MAINTAINER_, mtFee); _sync(); - return receiveBaseAmount; + emit DVMSwap( + address(_QUOTE_TOKEN_), + address(_BASE_TOKEN_), + quoteInput, + receiveBaseAmount, + tx.origin + ); } function flashLoan( @@ -84,7 +106,8 @@ contract DVMTrader is DVMVault { if (data.length > 0) IDODOCallee(assetTo).DVMFlashLoanCall(msg.sender, baseAmount, quoteAmount, data); - (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); + uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); + uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); // no input -> pure loss require( @@ -92,28 +115,40 @@ contract DVMTrader is DVMVault { "FLASH_LOAN_FAILED" ); + // sell quote if (baseBalance < _BASE_RESERVE_) { - (uint256 receiveBaseAmount, uint256 mtFee) = querySellQuote( - tx.origin, - quoteBalance.sub(_QUOTE_RESERVE_) - ); + uint256 quoteInput = quoteBalance.sub(_QUOTE_RESERVE_); + (uint256 receiveBaseAmount, uint256 mtFee) = querySellQuote(tx.origin, quoteInput); require(_BASE_RESERVE_.sub(baseBalance) <= receiveBaseAmount, "FLASH_LOAN_FAILED"); _transferBaseOut(_MAINTAINER_, mtFee); + emit DVMSwap( + address(_QUOTE_TOKEN_), + address(_BASE_TOKEN_), + quoteInput, + receiveBaseAmount, + tx.origin + ); } + // sell base if (quoteBalance < _QUOTE_RESERVE_) { - (uint256 receiveQuoteAmount, uint256 mtFee) = querySellBase( - tx.origin, - baseBalance.sub(_BASE_RESERVE_) - ); + uint256 baseInput = baseBalance.sub(_BASE_RESERVE_); + (uint256 receiveQuoteAmount, uint256 mtFee) = querySellBase(tx.origin, baseInput); require(_QUOTE_RESERVE_.sub(quoteBalance) <= receiveQuoteAmount, "FLASH_LOAN_FAILED"); _transferQuoteOut(_MAINTAINER_, mtFee); + emit DVMSwap( + address(_BASE_TOKEN_), + address(_QUOTE_TOKEN_), + baseInput, + receiveQuoteAmount, + tx.origin + ); } _sync(); } - // ============ View Functions ============ + // ============ Query Functions ============ function querySellBase(address trader, uint256 payBaseAmount) public @@ -128,8 +163,6 @@ contract DVMTrader is DVMVault { receiveQuoteAmount = receiveQuoteAmount .sub(DecimalMath.mulFloor(receiveQuoteAmount, lpFeeRate)) .sub(mtFee); - - return (receiveQuoteAmount, mtFee); } function querySellQuote(address trader, uint256 payQuoteAmount) @@ -145,7 +178,6 @@ contract DVMTrader is DVMVault { receiveBaseAmount = receiveBaseAmount .sub(DecimalMath.mulFloor(receiveBaseAmount, lpFeeRate)) .sub(mtFee); - return (receiveBaseAmount, mtFee); } // ============ Helper Functions ============ @@ -155,11 +187,10 @@ contract DVMTrader is DVMVault { state.K = _K_; state.B = _BASE_RESERVE_; state.Q = _QUOTE_RESERVE_; - state.B0 = 0; // recalculate in adjustedTarget + state.B0 = 0; // will be calculated in adjustedTarget state.Q0 = 0; state.R = PMMPricing.RState.ABOVE_ONE; PMMPricing.adjustedTarget(state); - return state; } function getMidPrice() public view returns (uint256 midPrice) { diff --git a/contracts/DODOVendingMachine/impl/DVMVault.sol b/contracts/DODOVendingMachine/impl/DVMVault.sol index 8a60262..0b3407b 100644 --- a/contracts/DODOVendingMachine/impl/DVMVault.sol +++ b/contracts/DODOVendingMachine/impl/DVMVault.sol @@ -28,23 +28,7 @@ contract DVMVault is DVMStorage { event Burn(address indexed user, uint256 value); - // Vault related - - function getVaultBalance() public view returns (uint256 baseBalance, uint256 quoteBalance) { - return (_BASE_TOKEN_.balanceOf(address(this)), _QUOTE_TOKEN_.balanceOf(address(this))); - } - - function getVaultReserve() public view returns (uint256 baseReserve, uint256 quoteReserve) { - return (_BASE_RESERVE_, _QUOTE_RESERVE_); - } - - function getBaseBalance() public view returns (uint256 baseBalance) { - return _BASE_TOKEN_.balanceOf(address(this)); - } - - function getQuoteBalance() public view returns (uint256 quoteBalance) { - return _QUOTE_TOKEN_.balanceOf(address(this)); - } + // ============ Asset In ============ function getBaseInput() public view returns (uint256 input) { return _BASE_TOKEN_.balanceOf(address(this)).sub(_BASE_RESERVE_); @@ -54,8 +38,11 @@ contract DVMVault is DVMStorage { return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_); } + // ============ Set States ============ + function _sync() internal { - (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); + uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); + uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); if (baseBalance != _BASE_RESERVE_) { _BASE_RESERVE_ = baseBalance; } @@ -64,6 +51,8 @@ contract DVMVault is DVMStorage { } } + // ============ Asset Out ============ + function _transferBaseOut(address to, uint256 amount) internal { if (amount > 0) { _BASE_TOKEN_.safeTransfer(to, amount); @@ -76,7 +65,8 @@ contract DVMVault is DVMStorage { } } - // Shares related + // ============ Shares (ERC20) ============ + /** * @dev transfer token for a specified address * @param to The address to transfer to. @@ -100,10 +90,6 @@ contract DVMVault is DVMStorage { return _SHARES_[owner]; } - function shareRatioOf(address owner) external view returns (uint256 shareRatio) { - return DecimalMath.divFloor(_SHARES_[owner], totalSupply); - } - /** * @dev Transfer tokens from one address to another * @param from address The address which you want to send tokens from diff --git a/contracts/SmartRoute/DODOV1Proxy01.sol b/contracts/SmartRoute/DODOV1Proxy01.sol index 200852e..585f268 100644 --- a/contracts/SmartRoute/DODOV1Proxy01.sol +++ b/contracts/SmartRoute/DODOV1Proxy01.sol @@ -13,7 +13,7 @@ import {UniversalERC20} from "./lib/UniversalERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; import {IDODOSellHelper} from "./intf/IDODOSellHelper.sol"; import {IDODOApprove} from "../intf/IDODOApprove.sol"; -import {IDODO} from "../intf/IDODO.sol"; +import {IDODOV1} from "./intf/IDODOV1.sol"; import {IWETH} from "../intf/IWETH.sol"; contract DODOV1Proxy01 is Ownable { @@ -77,19 +77,19 @@ contract DODOV1Proxy01 is Ownable { for (uint256 i = 0; i < dodoPairs.length; i++) { address curDodoPair = dodoPairs[i]; if (directions[i] == 0) { - address curDodoBase = IDODO(curDodoPair)._BASE_TOKEN_(); + address curDodoBase = IDODOV1(curDodoPair)._BASE_TOKEN_(); uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); IERC20(curDodoBase).universalApproveMax(curDodoPair, curAmountIn); - IDODO(curDodoPair).sellBaseToken(curAmountIn, 0, ""); + IDODOV1(curDodoPair).sellBaseToken(curAmountIn, 0, ""); } else { - address curDodoQuote = IDODO(curDodoPair)._QUOTE_TOKEN_(); + address curDodoQuote = IDODOV1(curDodoPair)._QUOTE_TOKEN_(); uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); IERC20(curDodoQuote).universalApproveMax(curDodoPair, curAmountIn); uint256 canBuyBaseAmount = IDODOSellHelper(dodoSellHelper).querySellQuoteToken( curDodoPair, curAmountIn ); - IDODO(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); + IDODOV1(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); } } diff --git a/contracts/intf/IDODO.sol b/contracts/SmartRoute/intf/IDODOV1.sol similarity index 99% rename from contracts/intf/IDODO.sol rename to contracts/SmartRoute/intf/IDODOV1.sol index 69d3d66..0f748fb 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/SmartRoute/intf/IDODOV1.sol @@ -8,8 +8,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; - -interface IDODO { +interface IDODOV1 { function init( address owner, address supervisor, @@ -78,4 +77,4 @@ interface IDODO { function getExpectedTarget() external view returns (uint256 baseTarget, uint256 quoteTarget); function getOraclePrice() external view returns (uint256); -} \ No newline at end of file +} diff --git a/contracts/helper/DODOSellHelper.sol b/contracts/SmartRoute/lib/DODOSellHelper.sol similarity index 90% rename from contracts/helper/DODOSellHelper.sol rename to contracts/SmartRoute/lib/DODOSellHelper.sol index 6b94b19..7f2ea00 100644 --- a/contracts/helper/DODOSellHelper.sol +++ b/contracts/SmartRoute/lib/DODOSellHelper.sol @@ -14,9 +14,9 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {IDODO} from "../intf/IDODO.sol"; -import {SafeMath} from "../lib/SafeMath.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; +import {IDODOV1} from "../intf/IDODOV1.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; // import {DODOMath} from "../lib/DODOMath.sol"; @@ -143,17 +143,17 @@ contract DODOSellHelper { } function querySellBaseToken(address dodo, uint256 amount) public view returns (uint256) { - return IDODO(dodo).querySellBaseToken(amount); + return IDODOV1(dodo).querySellBaseToken(amount); } function querySellQuoteToken(address dodo, uint256 amount) public view returns (uint256) { DODOState memory state; - (state.baseTarget, state.quoteTarget) = IDODO(dodo).getExpectedTarget(); - state.rStatus = RStatus(IDODO(dodo)._R_STATUS_()); - state.oraclePrice = IDODO(dodo).getOraclePrice(); - state.Q = IDODO(dodo)._QUOTE_BALANCE_(); - state.B = IDODO(dodo)._BASE_BALANCE_(); - state.K = IDODO(dodo)._K_(); + (state.baseTarget, state.quoteTarget) = IDODOV1(dodo).getExpectedTarget(); + state.rStatus = RStatus(IDODOV1(dodo)._R_STATUS_()); + state.oraclePrice = IDODOV1(dodo).getOraclePrice(); + state.Q = IDODOV1(dodo)._QUOTE_BALANCE_(); + state.B = IDODOV1(dodo)._BASE_BALANCE_(); + state.K = IDODOV1(dodo)._K_(); uint256 boughtAmount; // Determine the status (RStatus) and calculate the amount @@ -177,7 +177,9 @@ contract DODOSellHelper { return DecimalMath.divFloor( boughtAmount, - DecimalMath.ONE.add(IDODO(dodo)._MT_FEE_RATE_()).add(IDODO(dodo)._LP_FEE_RATE_()) + DecimalMath.ONE.add(IDODOV1(dodo)._MT_FEE_RATE_()).add( + IDODOV1(dodo)._LP_FEE_RATE_() + ) ); } diff --git a/contracts/helper/TestERC20.sol b/contracts/external/ERC20/TestERC20.sol similarity index 92% rename from contracts/helper/TestERC20.sol rename to contracts/external/ERC20/TestERC20.sol index a420d04..7e37f87 100644 --- a/contracts/helper/TestERC20.sol +++ b/contracts/external/ERC20/TestERC20.sol @@ -7,7 +7,7 @@ pragma solidity 0.6.9; -import {SafeMath} from "../lib/SafeMath.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; contract TestERC20 { using SafeMath for uint256; @@ -22,7 +22,11 @@ contract TestERC20 { event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); - constructor(string memory _name, uint8 _decimals,string memory _symbol) public { + constructor( + string memory _name, + uint8 _decimals, + string memory _symbol + ) public { name = _name; decimals = _decimals; symbol = _symbol; diff --git a/contracts/helper/TestWETH.sol b/contracts/helper/TestWETH.sol deleted file mode 100644 index 4ebf56c..0000000 --- a/contracts/helper/TestWETH.sol +++ /dev/null @@ -1,77 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; - - -contract WETH9 { - string public name = "Wrapped Ether"; - string public symbol = "WETH"; - uint8 public decimals = 18; - - event Approval(address indexed src, address indexed guy, uint256 wad); - event Transfer(address indexed src, address indexed dst, uint256 wad); - event Deposit(address indexed dst, uint256 wad); - event Withdrawal(address indexed src, uint256 wad); - - mapping(address => uint256) public balanceOf; - mapping(address => mapping(address => uint256)) public allowance; - - fallback() external payable { - deposit(); - } - - receive() external payable { - deposit(); - } - - function deposit() public payable { - balanceOf[msg.sender] += msg.value; - emit Deposit(msg.sender, msg.value); - } - - function withdraw(uint256 wad) public { - require(balanceOf[msg.sender] >= wad); - balanceOf[msg.sender] -= wad; - msg.sender.transfer(wad); - emit Withdrawal(msg.sender, wad); - } - - function totalSupply() public view returns (uint256) { - return address(this).balance; - } - - function approve(address guy, uint256 wad) public returns (bool) { - allowance[msg.sender][guy] = wad; - emit Approval(msg.sender, guy, wad); - return true; - } - - function transfer(address dst, uint256 wad) public returns (bool) { - return transferFrom(msg.sender, dst, wad); - } - - function transferFrom( - address src, - address dst, - uint256 wad - ) public returns (bool) { - require(balanceOf[src] >= wad); - - if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) { - require(allowance[src][msg.sender] >= wad); - allowance[src][msg.sender] -= wad; - } - - balanceOf[src] -= wad; - balanceOf[dst] += wad; - - Transfer(src, dst, wad); - - return true; - } -} diff --git a/contracts/intf/IVault.sol b/contracts/intf/IVault.sol deleted file mode 100644 index f616820..0000000 --- a/contracts/intf/IVault.sol +++ /dev/null @@ -1,15 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface IBasicVault { - function controller() external view returns(address); - function getReserve(address token) external view returns(address); - function transferOut(address token, address to, uint256 amount) external; -} \ No newline at end of file diff --git a/contracts/lib/CloneFactory.sol b/contracts/lib/CloneFactory.sol index 8837a5e..fd8f755 100644 --- a/contracts/lib/CloneFactory.sol +++ b/contracts/lib/CloneFactory.sol @@ -10,7 +10,6 @@ pragma experimental ABIEncoderV2; interface ICloneFactory { function clone(address prototype) external returns (address proxy); - function clone2(address prototype,bytes32 salt) external returns (address proxy); } // introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ @@ -31,20 +30,4 @@ contract CloneFactory is ICloneFactory { } return proxy; } - - - function clone2(address prototype, bytes32 salt) external override returns (address proxy) { - bytes20 targetBytes = bytes20(prototype); - assembly { - let clone := mload(0x40) - mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(clone, 0x14), targetBytes) - mstore( - add(clone, 0x28), - 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 - ) - proxy := create2(0, clone, 0x37, salt) - } - return proxy; - } } diff --git a/contracts/lib/PMMPricing.sol b/contracts/lib/PMMPricing.sol index 5487c83..2573324 100644 --- a/contracts/lib/PMMPricing.sol +++ b/contracts/lib/PMMPricing.sol @@ -34,6 +34,8 @@ library PMMPricing { RState R; } + // ============ buy & sell ============ + function sellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure @@ -75,8 +77,6 @@ library PMMPricing { receiveQuoteAmount = _RBelowSellBaseToken(state, payBaseAmount); newR = RState.BELOW_ONE; } - - return (receiveQuoteAmount, newR); } function sellQuoteToken(PMMState memory state, uint256 payQuoteAmount) @@ -109,8 +109,6 @@ library PMMPricing { newR = RState.ABOVE_ONE; } } - - return (receiveBaseAmount, newR); } // ============ R = 1 cases ============ @@ -118,7 +116,9 @@ library PMMPricing { function _ROneSellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure - returns (uint256 receiveQuoteToken) + returns ( + uint256 // receiveQuoteToken + ) { // in theory Q2 <= targetQuoteTokenAmount // however when amount is close to 0, precision problems may cause Q2 > targetQuoteTokenAmount @@ -135,7 +135,9 @@ library PMMPricing { function _ROneSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure - returns (uint256 receiveBaseToken) + returns ( + uint256 // receiveBaseToken + ) { return DODOMath._SolveQuadraticFunctionForTrade( @@ -152,7 +154,9 @@ library PMMPricing { function _RBelowSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure - returns (uint256 receiveBaseToken) + returns ( + uint256 // receiveBaseToken + ) { return DODOMath._GeneralIntegrate( @@ -167,7 +171,9 @@ library PMMPricing { function _RBelowSellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure - returns (uint256 receiveQuoteToken) + returns ( + uint256 // receiveQuoteToken + ) { return DODOMath._SolveQuadraticFunctionForTrade( @@ -184,7 +190,9 @@ library PMMPricing { function _RAboveSellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure - returns (uint256 receiveQuoteToken) + returns ( + uint256 // receiveQuoteToken + ) { return DODOMath._GeneralIntegrate( @@ -199,7 +207,9 @@ library PMMPricing { function _RAboveSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure - returns (uint256 receiveBaseToken) + returns ( + uint256 // receiveBaseToken + ) { return DODOMath._SolveQuadraticFunctionForTrade( @@ -231,7 +241,7 @@ library PMMPricing { } } - function getMidPrice(PMMState memory state) internal pure returns (uint256 midPrice) { + function getMidPrice(PMMState memory state) internal pure returns (uint256) { if (state.R == RState.BELOW_ONE) { uint256 R = DecimalMath.divFloor(state.Q0.mul(state.Q0).div(state.Q), state.Q); R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R)); diff --git a/test/DVM/funding.test.ts b/test/DVM/funding.test.ts index 0b45d47..c0e82ab 100644 --- a/test/DVM/funding.test.ts +++ b/test/DVM/funding.test.ts @@ -12,6 +12,7 @@ import { logGas } from '../utils/Log'; import { DVMContext, getDVMContext } from '../utils/DVMContext'; import { assert } from 'chai'; import BigNumber from 'bignumber.js'; +const truffleAssert = require('truffle-assertions'); let lp: string; let trader: string; @@ -95,7 +96,7 @@ describe("Funding", () => { assert.equal( await ctx.BASE.methods.balanceOf(ctx.DVM.options.address).call(), - "8856412162577279149" + "8856412162577279148" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.DVM.options.address).call(), @@ -154,11 +155,11 @@ describe("Funding", () => { var vaultShares = new BigNumber(await ctx.DVM.methods.balanceOf(lp).call()) var bob = ctx.SpareAccounts[5] - await ctx.DVM.methods.sellShares(vaultShares.div(2).toFixed(0), 0, 0, bob, "0x").send(ctx.sendParam(lp)) + await ctx.DVM.methods.sellShares(vaultShares.div(2).toFixed(0), bob, 0, 0, "0x").send(ctx.sendParam(lp)) assert.equal(await ctx.BASE.methods.balanceOf(bob).call(), decimalStr("5")) assert.equal(await ctx.QUOTE.methods.balanceOf(bob).call(), decimalStr("50")) - await ctx.DVM.methods.sellShares(vaultShares.div(2).toFixed(0), 0, 0, bob, "0x").send(ctx.sendParam(lp)) + await ctx.DVM.methods.sellShares(vaultShares.div(2).toFixed(0), bob, 0, 0, "0x").send(ctx.sendParam(lp)) assert.equal(await ctx.BASE.methods.balanceOf(bob).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(bob).call(), decimalStr("100")) }) @@ -170,9 +171,30 @@ describe("Funding", () => { var vaultShares = await ctx.DVM.methods.balanceOf(lp).call() var bob = ctx.SpareAccounts[5] - await ctx.DVM.methods.sellShares(vaultShares, 0, 0, bob, "0x").send(ctx.sendParam(lp)) + await ctx.DVM.methods.sellShares(vaultShares, bob, 0, 0, "0x").send(ctx.sendParam(lp)) assert.equal(await ctx.BASE.methods.balanceOf(bob).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(bob).call(), decimalStr("100")) }) + + it("revert cases", async () => { + await ctx.transferBaseToDVM(lp, decimalStr("10")) + await ctx.transferQuoteToDVM(lp, decimalStr("100")) + await ctx.DVM.methods.buyShares(lp).send(ctx.sendParam(lp)) + + var vaultShares = await ctx.DVM.methods.balanceOf(lp).call() + var bob = ctx.SpareAccounts[5] + await truffleAssert.reverts( + ctx.DVM.methods.sellShares(new BigNumber(vaultShares).multipliedBy(2), bob, 0, 0, "0x").send(ctx.sendParam(lp)), + "DLP_NOT_ENOUGH" + ) + await truffleAssert.reverts( + ctx.DVM.methods.sellShares(vaultShares, bob, decimalStr("100"), 0, "0x").send(ctx.sendParam(lp)), + "WITHDRAW_NOT_ENOUGH" + ) + await truffleAssert.reverts( + ctx.DVM.methods.sellShares(vaultShares, bob, 0, decimalStr("10000"), "0x").send(ctx.sendParam(lp)), + "WITHDRAW_NOT_ENOUGH" + ) + }) }) }); diff --git a/test/DVM/trader.test.ts b/test/DVM/trader.test.ts index dc19452..3fe1cad 100644 --- a/test/DVM/trader.test.ts +++ b/test/DVM/trader.test.ts @@ -26,8 +26,6 @@ async function init(ctx: DVMContext): Promise { await ctx.transferBaseToDVM(lp, decimalStr("10")) await ctx.DVM.methods.buyShares(lp).send(ctx.sendParam(lp)) - - console.log("deposit") } describe("Trader", () => { @@ -48,39 +46,35 @@ describe("Trader", () => { }); describe("trade", () => { - it.only("basic check", async () => { - console.log(await ctx.DVM.methods.symbol().call()) - console.log(await ctx.DVM.methods.decimals().call()) - console.log(await ctx.DVM.methods.name().call()) - // console.log(await ctx.DVM.methods.getVaultReserve().call()) - // console.log(await ctx.DVM.methods.getPMMState().call()) - // console.log(await ctx.DVM.methods.getMidPrice().call()) - // console.log(await ctx.DVM.methods.querySellQuote(ctx.Deployer, decimalStr("200")).call()) - // console.log(ctx.BASE.options.address) - // console.log(await ctx.DVM.methods._BASE_TOKEN_().call()) - // console.log(ctx.QUOTE.options.address) - // console.log(await ctx.DVM.methods._QUOTE_TOKEN_().call()) - }) - - // it.only("mannually buy", async () => { - // await ctx.QUOTE.methods.transfer(ctx.DVM.options.address, decimalStr("100")).send(ctx.sendParam(lp)) - // console.log(await ctx.DVM.methods.getQuoteInput().call()) - // console.log(await ctx.DVM.methods.querySellQuote(lp, decimalStr("100")).call()) - // await ctx.DVM.methods.sellQuote(lp).send(ctx.sendParam(lp)) + // it.only("basic check", async () => { + // console.log(await ctx.DVM.methods.symbol().call()) + // console.log(await ctx.DVM.methods.decimals().call()) + // console.log(await ctx.DVM.methods.name().call()) + // console.log(await ctx.DVM.methods.getVaultReserve().call()) + // console.log(await ctx.DVM.methods.getPMMState().call()) + // console.log(await ctx.DVM.methods.getMidPrice().call()) + // console.log(await ctx.DVM.methods.querySellQuote(ctx.Deployer, decimalStr("200")).call()) + // console.log(ctx.BASE.options.address) + // console.log(await ctx.DVM.methods._BASE_TOKEN_().call()) + // console.log(ctx.QUOTE.options.address) + // console.log(await ctx.DVM.methods._QUOTE_TOKEN_().call()) // }) - it("buy & sell", async () => { + it("DVM ERC20 Shares info", async () => { + console.log("DVM symbol", await ctx.DVM.methods.symbol().call()) + console.log("DVM decimals", await ctx.DVM.methods.decimals().call()) + console.log("DVM name", await ctx.DVM.methods.name().call()) + }) - console.log("BASE0 before buy", await ctx.DVM.methods.getBase0().call()) + it("buy & sell", async () => { // buy await ctx.transferQuoteToDVM(trader, decimalStr("200")) await logGas(ctx.DVM.methods.sellQuote(trader), ctx.sendParam(trader), "buy base token") - console.log("BASE0 after buy", await ctx.DVM.methods.getBase0().call()) // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), - "11946763594380080787" + "11946763594380080789" ); assert.equal( await ctx.QUOTE.methods.balanceOf(trader).call(), @@ -89,7 +83,7 @@ describe("Trader", () => { // vault balances assert.equal( await ctx.BASE.methods.balanceOf(ctx.DVM.options.address).call(), - "8051283784161162863" + "8051283784161162862" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.DVM.options.address).call(), @@ -98,7 +92,7 @@ describe("Trader", () => { // maintainer balances assert.equal( await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), - "1952621458756350" + "1952621458756349" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), @@ -108,65 +102,63 @@ describe("Trader", () => { // sell await ctx.transferBaseToDVM(trader, decimalStr("1")) await logGas(ctx.DVM.methods.sellBase(trader), ctx.sendParam(trader), "sell base token") - console.log("BASE0 after sell", await ctx.DVM.methods.getBase0().call()) // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), - "10946763594380080787" + "10946763594380080789" ); assert.equal( await ctx.QUOTE.methods.balanceOf(trader).call(), - "903421810640399874603" + "903421810640399874605" ); // vault balances assert.equal( await ctx.BASE.methods.balanceOf(ctx.DVM.options.address).call(), - "9051283784161162863" + "9051283784161162862" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.DVM.options.address).call(), - "96474456349930717298" + "96474456349930717297" ); // maintainer balances assert.equal( await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), - "1952621458756350" + "1952621458756349" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), - "103733009669408099" + "103733009669408098" ); // buy when quoet is not 0 await ctx.transferQuoteToDVM(trader, decimalStr("200")) await logGas(ctx.DVM.methods.sellQuote(trader), ctx.sendParam(trader), "buy base token") - console.log("BASE0 after second buy", await ctx.DVM.methods.getBase0().call()) // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), - "12837528824326616010" + "12837528824326616014" ); assert.equal( await ctx.QUOTE.methods.balanceOf(trader).call(), - "703421810640399874603" + "703421810640399874605" ); // vault balances assert.equal( await ctx.BASE.methods.balanceOf(ctx.DVM.options.address).call(), - "7158622099620899921" + "7158622099620899919" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.DVM.options.address).call(), - "296474456349930717298" + "296474456349930717297" ); // maintainer balances assert.equal( await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), - "3849076052484069" + "3849076052484067" ); assert.equal( await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), - "103733009669408099" + "103733009669408098" ); }); @@ -175,30 +167,30 @@ describe("Trader", () => { 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") + await truffleAssert.reverts(ctx.DVM.methods.flashLoan("1946763594380080790", "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)) + await ctx.DVM.methods.flashLoan("1946763594380080789", "0", trader, "0x").send(ctx.sendParam(trader)) // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), - "11946763594380080787" + "11946763594380080789" ); // 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") + await truffleAssert.reverts(ctx.DVM.methods.flashLoan("0", "103421810640399874606", trader, "0x").send(ctx.sendParam(trader)), "FLASH_LOAN_FAILED") // sell succeed - await ctx.DVM.methods.flashLoan("0", "103421810640399874603", trader, "0x").send(ctx.sendParam(trader)) + await ctx.DVM.methods.flashLoan("0", "103421810640399874605", trader, "0x").send(ctx.sendParam(trader)) // trader balances assert.equal( await ctx.QUOTE.methods.balanceOf(trader).call(), - "903421810640399874603" + "903421810640399874605" ); })