diff --git a/contracts/DODOVenderMachine/DVMFactory.sol b/contracts/DODOVendorMachine/DVMFactory.sol similarity index 63% rename from contracts/DODOVenderMachine/DVMFactory.sol rename to contracts/DODOVendorMachine/DVMFactory.sol index 5218a23..4d5623a 100644 --- a/contracts/DODOVenderMachine/DVMFactory.sol +++ b/contracts/DODOVendorMachine/DVMFactory.sol @@ -31,7 +31,7 @@ contract DVMFactory is Ownable { _CONTROLLER_TEMPLATE_ = controllerTemplate; } - function createDODOVenderMachine( + function createDODOVendorMachine( address maintainer, address baseToken, address quoteToken, @@ -40,17 +40,15 @@ contract DVMFactory is Ownable { uint256 i, uint256 k, uint256 gasPriceLimit - ) external returns (address newVenderMachine) { - DVMController controller = DVMController( - ICloneFactory(_CLONE_FACTORY_).clone(_CONTROLLER_TEMPLATE_) - ); - DVMVault vault = DVMVault(ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_)); - vault.init(address(controller), baseToken, quoteToken); // vault owner is controller + ) external returns (address newVendorMachine) { + newVendorMachine = ICloneFactory(_CLONE_FACTORY_).clone(_CONTROLLER_TEMPLATE_); + address vault = ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_); + DVMVault(vault).init(newVendorMachine, baseToken, quoteToken); // vault owner is controller - controller.init( + DVMController(newVendorMachine).init( msg.sender, maintainer, - address(vault), + vault, lpFeeRateModel, mtFeeRateModel, i, @@ -58,8 +56,15 @@ contract DVMFactory is Ownable { gasPriceLimit ); - newVenderMachine = address(controller); - _REGISTRY_[baseToken][quoteToken].push(newVenderMachine); - return newVenderMachine; + _REGISTRY_[baseToken][quoteToken].push(newVendorMachine); + return newVendorMachine; + } + + function getVendorMachine(address baseToken, address quoteToken) + external + view + returns (address[] memory machines) + { + return _REGISTRY_[baseToken][quoteToken]; } } diff --git a/contracts/DODOVenderMachine/impl/DVMAdmin.sol b/contracts/DODOVendorMachine/impl/DVMAdmin.sol similarity index 100% rename from contracts/DODOVenderMachine/impl/DVMAdmin.sol rename to contracts/DODOVendorMachine/impl/DVMAdmin.sol diff --git a/contracts/DODOVenderMachine/impl/DVMController.sol b/contracts/DODOVendorMachine/impl/DVMController.sol similarity index 87% rename from contracts/DODOVenderMachine/impl/DVMController.sol rename to contracts/DODOVendorMachine/impl/DVMController.sol index 26b4920..5abb225 100644 --- a/contracts/DODOVenderMachine/impl/DVMController.sol +++ b/contracts/DODOVendorMachine/impl/DVMController.sol @@ -27,8 +27,9 @@ contract DVMController is DVMTrader, DVMFunding, DVMAdmin { ) external { initOwner(owner); _MAINTAINER_ = maintainer; - _BASE_TOKEN_ = DVMVault(vault)._BASE_TOKEN_(); - _QUOTE_TOKEN_ = DVMVault(vault)._QUOTE_TOKEN_(); + _VAULT_ = DVMVault(vault); + _BASE_TOKEN_ = _VAULT_._BASE_TOKEN_(); + _QUOTE_TOKEN_ = _VAULT_._QUOTE_TOKEN_(); _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); _I_ = i; diff --git a/contracts/DODOVenderMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol similarity index 54% rename from contracts/DODOVenderMachine/impl/DVMFunding.sol rename to contracts/DODOVendorMachine/impl/DVMFunding.sol index 34d8f9a..04fbc61 100644 --- a/contracts/DODOVenderMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -15,41 +15,35 @@ contract DVMFunding is DVMStorage { function buyShares(address account) external returns (uint256) { uint256 baseInput = _VAULT_.getBaseInput(); uint256 quoteInput = _VAULT_.getQuoteInput(); - require(baseInput > 0, "NO_BASE_INPUT"); - uint256 baseReserve = _VAULT_._BASE_RESERVE_(); uint256 quoteReserve = _VAULT_._QUOTE_RESERVE_(); uint256 mintAmount; - // case 1. initial supply if (baseReserve == 0 && quoteReserve == 0) { mintAmount = baseInput; } - - // case 2. supply when quote reserve is 0 - if (baseReserve > 0 && quoteReserve == 0) { - uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); - mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); - } - - // case 3. normal case - if (baseReserve > 0 && quoteReserve > 0) { - uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); - uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); - uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; - // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 - // 但有可能出现,reserve>0但totalSupply=0的场景 - uint256 totalShare = _VAULT_.totalSupply(); - if (totalShare > 0) { - mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); - } else { - mintAmount = baseInput; - } - } - - _VAULT_.mint(account, mintAmount); - _VAULT_.sync(); + // // case 2. supply when quote reserve is 0 + // if (baseReserve > 0 && quoteReserve == 0) { + // uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); + // mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); + // } + // // case 3. normal case + // if (baseReserve > 0 && quoteReserve > 0) { + // uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); + // uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); + // uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; + // // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 + // // 但有可能出现,reserve>0但totalSupply=0的场景 + // uint256 totalShare = _VAULT_.totalSupply(); + // if (totalShare > 0) { + // mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); + // } else { + // mintAmount = baseInput; + // } + // } + // _VAULT_.mint(account, mintAmount); + // _VAULT_.sync(); } function sellShares( diff --git a/contracts/DODOVenderMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol similarity index 100% rename from contracts/DODOVenderMachine/impl/DVMStorage.sol rename to contracts/DODOVendorMachine/impl/DVMStorage.sol diff --git a/contracts/DODOVenderMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol similarity index 100% rename from contracts/DODOVenderMachine/impl/DVMTrader.sol rename to contracts/DODOVendorMachine/impl/DVMTrader.sol diff --git a/contracts/DODOVenderMachine/impl/DVMVault.sol b/contracts/DODOVendorMachine/impl/DVMVault.sol similarity index 98% rename from contracts/DODOVenderMachine/impl/DVMVault.sol rename to contracts/DODOVendorMachine/impl/DVMVault.sol index 2f6c968..5e0e5d9 100644 --- a/contracts/DODOVenderMachine/impl/DVMVault.sol +++ b/contracts/DODOVendorMachine/impl/DVMVault.sol @@ -66,6 +66,8 @@ contract DVMVault is InitializableOwnable { ); symbol = "DLP"; decimals = IERC20(_baseToken).decimals(); + _BASE_TOKEN_ = _baseToken; + _QUOTE_TOKEN_ = _quoteToken; } // Vault related diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index 26f2eb1..57f9718 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -8,8 +8,8 @@ pragma solidity 0.6.9; import {Ownable} from "../lib/Ownable.sol"; -import {DVMController} from "../DODOVenderMachine/impl/DVMController.sol"; -import {DVMVault} from "../DODOVenderMachine/impl/DVMVault.sol"; +import {DVMController} from "../DODOVendorMachine/impl/DVMController.sol"; +import {DVMVault} from "../DODOVendorMachine/impl/DVMVault.sol"; import {IERC20} from "../intf/IERC20.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; diff --git a/contracts/external/ERC20/NormalERC20.sol b/contracts/external/ERC20/MintableERC20.sol similarity index 91% rename from contracts/external/ERC20/NormalERC20.sol rename to contracts/external/ERC20/MintableERC20.sol index 416b1e8..32f94df 100644 --- a/contracts/external/ERC20/NormalERC20.sol +++ b/contracts/external/ERC20/MintableERC20.sol @@ -9,10 +9,11 @@ pragma solidity 0.6.9; import {SafeMath} from "../../lib/SafeMath.sol"; -contract TestERC20 { +contract MintableERC20 { using SafeMath for uint256; string public name; + string public symbol; uint8 public decimals; mapping(address => uint256) balances; @@ -21,8 +22,13 @@ 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) public { + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) public { name = _name; + symbol = _symbol; decimals = _decimals; } diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 434e5b6..63ed46d 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -1,3 +1 @@ -const DODOZoo = artifacts.require("DODOZoo"); - module.exports = async (deployer, network) => {}; diff --git a/test/DVM/trader.ts b/test/DVM/trader.ts new file mode 100644 index 0000000..bc6b435 --- /dev/null +++ b/test/DVM/trader.ts @@ -0,0 +1,85 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// import * as assert from 'assert'; + +import { decimalStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { DVMContext, getDVMContext } from '../utils/DVMContext'; +import { DVM_VAULT_NAME, getContractWithAddress } from '../utils/Contracts'; +import { Contract } from 'web3-eth-contract'; + +let lp: string; +let trader: string; +let vault: Contract + +async function init(ctx: DVMContext): Promise { + lp = ctx.SpareAccounts[0]; + trader = ctx.SpareAccounts[1]; + await ctx.approveRoute(lp); + await ctx.approveRoute(trader); + + console.log("approve") + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + + console.log("mint") + + var vaultAddress = await ctx.DVM.methods._VAULT_().call(); + vault = getContractWithAddress(DVM_VAULT_NAME, vaultAddress) + + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + .send(ctx.sendParam(lp)); + + console.log(await vault.methods.getVaultBalance().call()) + + console.log("deposit") +} + +describe("Trader", () => { + let snapshotId: string; + let ctx: DVMContext; + + before(async () => { + ctx = await getDVMContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("trade", () => { + it("buy when R equals ONE", async () => { + await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("90")), ctx.sendParam(trader), "buy base token when balanced") + // trader balances + console.log( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("11") + ); + console.log( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "898581839502056240973" + ); + // maintainer balances + console.log( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.001") + ); + console.log( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0") + ); + }); + }); +}); diff --git a/test/Admin.test.ts b/test/V1/Admin.test.ts similarity index 100% rename from test/Admin.test.ts rename to test/V1/Admin.test.ts diff --git a/test/Attacks.test.ts b/test/V1/Attacks.test.ts similarity index 100% rename from test/Attacks.test.ts rename to test/V1/Attacks.test.ts diff --git a/test/DODOEthProxyAsBase.test.ts b/test/V1/DODOEthProxyAsBase.test.ts similarity index 100% rename from test/DODOEthProxyAsBase.test.ts rename to test/V1/DODOEthProxyAsBase.test.ts diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/V1/DODOEthProxyAsQuote.test.ts similarity index 100% rename from test/DODOEthProxyAsQuote.test.ts rename to test/V1/DODOEthProxyAsQuote.test.ts diff --git a/test/DODOZoo.test.ts b/test/V1/DODOZoo.test.ts similarity index 100% rename from test/DODOZoo.test.ts rename to test/V1/DODOZoo.test.ts diff --git a/test/LiquidityProvider.test.ts b/test/V1/LiquidityProvider.test.ts similarity index 100% rename from test/LiquidityProvider.test.ts rename to test/V1/LiquidityProvider.test.ts diff --git a/test/LongTailTokenlMode.test.ts b/test/V1/LongTailTokenlMode.test.ts similarity index 100% rename from test/LongTailTokenlMode.test.ts rename to test/V1/LongTailTokenlMode.test.ts diff --git a/test/Mining.test.ts b/test/V1/Mining.test.ts similarity index 100% rename from test/Mining.test.ts rename to test/V1/Mining.test.ts diff --git a/test/Rebalance.test.ts b/test/V1/Rebalance.test.ts similarity index 100% rename from test/Rebalance.test.ts rename to test/V1/Rebalance.test.ts diff --git a/test/StableCoinMode.test.ts b/test/V1/StableCoinMode.test.ts similarity index 100% rename from test/StableCoinMode.test.ts rename to test/V1/StableCoinMode.test.ts diff --git a/test/TokenLock.test.ts b/test/V1/TokenLock.test.ts similarity index 100% rename from test/TokenLock.test.ts rename to test/V1/TokenLock.test.ts diff --git a/test/Trader.test.ts b/test/V1/Trader.test.ts similarity index 100% rename from test/Trader.test.ts rename to test/V1/Trader.test.ts diff --git a/test/UniswapArbitrageur.test.ts b/test/V1/UniswapArbitrageur.test.ts similarity index 100% rename from test/UniswapArbitrageur.test.ts rename to test/V1/UniswapArbitrageur.test.ts diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index fabcb07..fae2178 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -15,7 +15,7 @@ import { Contract } from 'web3-eth-contract'; export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" export const DODO_CONTRACT_NAME = "DODO" -export const TEST_ERC20_CONTRACT_NAME = "TestERC20" +export const MINTABLE_ERC20_CONTRACT_NAME = "MintableERC20" export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" diff --git a/test/utils/DVMContext.ts b/test/utils/DVMContext.ts index 4c9c539..fa6adb8 100644 --- a/test/utils/DVMContext.ts +++ b/test/utils/DVMContext.ts @@ -77,12 +77,12 @@ export class DVMContext { this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, [cloneFactory.options.address, vaultTemplate.options.address, controllerTemplate.options.address]) this.BASE = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["TestBase", 18] + contracts.MINTABLE_ERC20_CONTRACT_NAME, + ["TestBase", "BASE", 18] ); this.QUOTE = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["TestQuote", 18] + contracts.MINTABLE_ERC20_CONTRACT_NAME, + ["TestQuote", "QUOTE", 18] ); const allAccounts = await this.Web3.eth.getAccounts(); @@ -92,7 +92,7 @@ export class DVMContext { var lpFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.lpFeeRate]) var mtFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.mtFeeRate]) - var DVMAddress = this.DVMFactory.methods.createDODOVenderMachine( + await this.DVMFactory.methods.createDODOVendorMachine( this.Maintainer, this.BASE.options.address, this.QUOTE.options.address, @@ -102,7 +102,8 @@ export class DVMContext { config.k, config.gasPriceLimit).send(this.sendParam(this.Deployer)) - this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, DVMAddress) + var vendorMachines = await this.DVMFactory.methods.getVendorMachine(this.BASE.options.address, this.QUOTE.options.address).call() + this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, vendorMachines[0]) console.log(log.blueText("[Init DVM context]")); } @@ -133,7 +134,7 @@ export class DVMContext { } } -export async function getDODOContext( +export async function getDVMContext( config: DVMContextInitConfig = DefaultDVMContextInitConfig ): Promise { var context = new DVMContext();