This commit is contained in:
mingda
2020-11-05 14:10:59 +08:00
parent 4a7c5a546d
commit b31f1a30e2
8 changed files with 68 additions and 37 deletions

View File

@@ -12,7 +12,7 @@ import {DVMStorage} from "./DVMStorage.sol";
import {DecimalMath} from "../../lib/DecimalMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol";
contract DVMFunding is DVMStorage { contract DVMFunding is DVMStorage {
function buyShares(address account) external returns (uint256) { function buyShares(address to) external returns (uint256) {
uint256 baseInput = _VAULT_.getBaseInput(); uint256 baseInput = _VAULT_.getBaseInput();
uint256 quoteInput = _VAULT_.getQuoteInput(); uint256 quoteInput = _VAULT_.getQuoteInput();
require(baseInput > 0, "NO_BASE_INPUT"); require(baseInput > 0, "NO_BASE_INPUT");
@@ -42,22 +42,28 @@ contract DVMFunding is DVMStorage {
mintAmount = baseInput; mintAmount = baseInput;
} }
} }
_VAULT_.mint(account, mintAmount); _VAULT_.mint(to, mintAmount);
_VAULT_.sync(); _VAULT_.sync();
} }
function sellShares( function sellShares(address to, uint256 amount) external returns (uint256) {
address account, require(_VAULT_.balanceOf(msg.sender) >= amount, "SHARES_NOT_ENOUGH");
address to,
uint256 amount
) external returns (uint256) {
require(msg.sender == account, "PERMISSION_DENY");
require(_VAULT_.balanceOf(account) >= amount, "SHARES_NOT_ENOUGH");
(uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance();
uint256 totalShares = _VAULT_.totalSupply(); uint256 totalShares = _VAULT_.totalSupply();
_VAULT_.burn(account, amount); _VAULT_.burn(msg.sender, amount);
_VAULT_.transferBaseOut(to, baseBalance.mul(amount).div(totalShares)); _VAULT_.transferBaseOut(to, baseBalance.mul(amount).div(totalShares));
_VAULT_.transferQuoteOut(to, quoteBalance.mul(amount).div(totalShares)); _VAULT_.transferQuoteOut(to, quoteBalance.mul(amount).div(totalShares));
_VAULT_.sync(); _VAULT_.sync();
} }
function retrieve(address to) external {
(uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance();
(uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve();
if (baseBalance.sub(baseReserve) > 0) {
_VAULT_.transferBaseOut(to, baseBalance.sub(baseReserve));
}
if (quoteBalance.sub(quoteReserve) > 0) {
_VAULT_.transferQuoteOut(to, quoteBalance.sub(quoteReserve));
}
}
} }

View File

@@ -58,7 +58,13 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard {
// ============ Helper Functions ============ // ============ Helper Functions ============
function getBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) {
uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_);
return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount);
}
function getBase0() public view returns (uint256) {
(uint256 baseAmount, uint256 quoteAmount) = _VAULT_.getVaultReserve();
uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_);
return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount);
} }

View File

@@ -49,7 +49,7 @@ contract DVMTrader is DVMStorage {
bytes calldata data bytes calldata data
) external { ) external {
(uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve();
uint256 B0 = getBase0(baseReserve, quoteReserve); uint256 B0 = calculateBase0(baseReserve, quoteReserve);
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo, quoteAmount); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo, quoteAmount);
uint256 baseMtFee = DecimalMath.mulCeil(baseAmount, mtFeeRate); uint256 baseMtFee = DecimalMath.mulCeil(baseAmount, mtFeeRate);
@@ -63,7 +63,7 @@ contract DVMTrader is DVMStorage {
IExternalCall(call).DVMCall(data); IExternalCall(call).DVMCall(data);
(uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance();
uint256 newB0 = getBase0(baseBalance, quoteBalance); uint256 newB0 = calculateBase0(baseBalance, quoteBalance);
require(newB0 >= B0, "FLASH_LOAN_FAILED"); require(newB0 >= B0, "FLASH_LOAN_FAILED");
_VAULT_.sync(); _VAULT_.sync();
} }
@@ -74,7 +74,7 @@ contract DVMTrader is DVMStorage {
returns (uint256 receiveQuoteAmount, uint256 mtFee) returns (uint256 receiveQuoteAmount, uint256 mtFee)
{ {
(uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve();
uint256 B0 = getBase0(baseReserve, quoteReserve); uint256 B0 = calculateBase0(baseReserve, quoteReserve);
uint256 B1 = baseReserve.add(payBaseAmount); uint256 B1 = baseReserve.add(payBaseAmount);
require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH");
@@ -94,7 +94,7 @@ contract DVMTrader is DVMStorage {
returns (uint256 receiveBaseAmount, uint256 mtFee) returns (uint256 receiveBaseAmount, uint256 mtFee)
{ {
(uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve();
uint256 B0 = getBase0(baseReserve, quoteReserve); uint256 B0 = calculateBase0(baseReserve, quoteReserve);
uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_);
uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade(
@@ -114,7 +114,7 @@ contract DVMTrader is DVMStorage {
function getMidPrice() public view returns (uint256 midPrice) { function getMidPrice() public view returns (uint256 midPrice) {
(uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve();
uint256 B0 = getBase0(baseReserve, quoteReserve); uint256 B0 = calculateBase0(baseReserve, quoteReserve);
uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(baseReserve).mul(B0).div(baseReserve); uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(baseReserve).mul(B0).div(baseReserve);
uint256 offset = DecimalMath.ONE.sub(_K_).add(DecimalMath.mulFloor(offsetRatio, _K_)); uint256 offset = DecimalMath.ONE.sub(_K_).add(DecimalMath.mulFloor(offsetRatio, _K_));

View File

@@ -95,6 +95,8 @@ contract SmartRoute is Ownable {
adjustedQuoteAmount adjustedQuoteAmount
); );
return DVM(DVMAddress).buyShares(to); shares = DVM(DVMAddress).buyShares(to);
return shares;
} }
} }

View File

@@ -141,4 +141,17 @@ describe("Funding", () => {
assert.equal(await ctx.Vault.methods.balanceOf(trader).call(), "499999999999999990") assert.equal(await ctx.Vault.methods.balanceOf(trader).call(), "499999999999999990")
}) })
}); });
describe("sell shares", () => {
it("sell shares", async () => {
await ctx.Route.methods
.depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("100"))
.send(ctx.sendParam(lp));
var vaultShares = await ctx.Vault.methods.balanceOf(lp).call()
var bob = ctx.SpareAccounts[0]
await ctx.DVM.methods.sellShares(bob, vaultShares).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"))
})
})
}); });

View File

@@ -53,11 +53,11 @@ describe("Trader", () => {
describe("trade", () => { describe("trade", () => {
it("buy & sell", async () => { it("buy & sell", async () => {
console.log("BASE0 before buy", await ctx.DVM.methods._BASE0_().call()) console.log("BASE0 before buy", await ctx.DVM.methods.getBase0().call())
// buy // buy
await logGas(ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "buy base token") await logGas(ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "buy base token")
console.log("BASE0 after buy", await ctx.DVM.methods._BASE0_().call()) console.log("BASE0 after buy", await ctx.DVM.methods.getBase0().call())
// trader balances // trader balances
assert.equal( assert.equal(
await ctx.BASE.methods.balanceOf(trader).call(), await ctx.BASE.methods.balanceOf(trader).call(),
@@ -88,7 +88,7 @@ describe("Trader", () => {
// sell // sell
await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("100")), ctx.sendParam(trader), "sell base token") await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("100")), ctx.sendParam(trader), "sell base token")
console.log("BASE0 after sell", await ctx.DVM.methods._BASE0_().call()) console.log("BASE0 after sell", await ctx.DVM.methods.getBase0().call())
// trader balances // trader balances
assert.equal( assert.equal(
await ctx.BASE.methods.balanceOf(trader).call(), await ctx.BASE.methods.balanceOf(trader).call(),

View File

@@ -29,10 +29,11 @@ export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault"
export const DODO_MINE_NAME = "DODOMine" export const DODO_MINE_NAME = "DODOMine"
export const DODO_MINE_READER_NAME = "DODOMineReader" export const DODO_MINE_READER_NAME = "DODOMineReader"
export const DVM_VAULT_NAME = "DVMVault" export const DVM_VAULT_NAME = "DVMVault"
export const DVM_CONTROLLER_NAME = "DVMController" export const DVM_NAME = "DVM"
export const DVM_FACTORY_NAME = "DVMFactory" export const DVM_FACTORY_NAME = "DVMFactory"
export const SMART_ROUTE_NAME = "SmartRoute" export const SMART_ROUTE_NAME = "SmartRoute"
export const NAIVE_FEE_RATE_MODEL_NAME = "NaiveFeeRateModel" export const CONST_FEE_RATE_MODEL_NAME = "ConstFeeRateModel"
export const PERMISSION_MANAGER_NAME = "PermissionManager"
interface ContractJson { interface ContractJson {
abi: any; abi: any;

View File

@@ -10,7 +10,7 @@ import Web3 from 'web3';
import { Contract } from 'web3-eth-contract'; import { Contract } from 'web3-eth-contract';
import * as contracts from './Contracts'; import * as contracts from './Contracts';
import { decimalStr, gweiStr, MAX_UINT256 } from './Converter'; import { decimalStr, MAX_UINT256 } from './Converter';
import { EVM, getDefaultWeb3 } from './EVM'; import { EVM, getDefaultWeb3 } from './EVM';
import * as log from './Log'; import * as log from './Log';
@@ -24,7 +24,6 @@ export interface DVMContextInitConfig {
mtFeeRate: string; mtFeeRate: string;
k: string; k: string;
i: string; i: string;
gasPriceLimit: string;
} }
/* /*
@@ -45,7 +44,6 @@ export let DefaultDVMContextInitConfig = {
mtFeeRate: decimalStr("0.001"), mtFeeRate: decimalStr("0.001"),
k: decimalStr("0.1"), k: decimalStr("0.1"),
i: decimalStr("100"), i: decimalStr("100"),
gasPriceLimit: gweiStr("100"),
}; };
export class DVMContext { export class DVMContext {
@@ -72,9 +70,16 @@ export class DVMContext {
contracts.CLONE_FACTORY_CONTRACT_NAME contracts.CLONE_FACTORY_CONTRACT_NAME
); );
var vaultTemplate = await contracts.newContract(contracts.DVM_VAULT_NAME) var vaultTemplate = await contracts.newContract(contracts.DVM_VAULT_NAME)
var controllerTemplate = await contracts.newContract(contracts.DVM_CONTROLLER_NAME) var dvmTemplate = await contracts.newContract(contracts.DVM_NAME)
var feeRateModelTemplate = await contracts.newContract(contracts.CONST_FEE_RATE_MODEL_NAME)
var permissionManagerTemplate = await contracts.newContract(contracts.PERMISSION_MANAGER_NAME)
this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, [cloneFactory.options.address, vaultTemplate.options.address, controllerTemplate.options.address]) this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME,
[cloneFactory.options.address,
vaultTemplate.options.address,
dvmTemplate.options.address,
feeRateModelTemplate.options.address,
permissionManagerTemplate.options.address])
this.BASE = await contracts.newContract( this.BASE = await contracts.newContract(
contracts.MINTABLE_ERC20_CONTRACT_NAME, contracts.MINTABLE_ERC20_CONTRACT_NAME,
@@ -90,23 +95,21 @@ export class DVMContext {
this.Maintainer = allAccounts[1]; this.Maintainer = allAccounts[1];
this.SpareAccounts = allAccounts.slice(2, 10); this.SpareAccounts = allAccounts.slice(2, 10);
var lpFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.lpFeeRate]) await this.DVMFactory.methods.createStandardDODOVendorMachine(
var mtFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.mtFeeRate])
await this.DVMFactory.methods.createDODOVendorMachine(
this.Maintainer,
this.BASE.options.address, this.BASE.options.address,
this.QUOTE.options.address, this.QUOTE.options.address,
lpFeeRateModel.options.address, config.lpFeeRate,
mtFeeRateModel.options.address, config.mtFeeRate,
config.i, config.i,
config.k, config.k
config.gasPriceLimit).send(this.sendParam(this.Deployer)) ).send(this.sendParam(this.Deployer))
var vendorMachines = await this.DVMFactory.methods.getVendorMachine(this.BASE.options.address, this.QUOTE.options.address).call() 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]) this.DVM = contracts.getContractWithAddress(contracts.DVM_NAME, vendorMachines[0])
this.Vault = contracts.getContractWithAddress(contracts.DVM_VAULT_NAME, await this.DVM.methods._VAULT_().call()) this.Vault = contracts.getContractWithAddress(contracts.DVM_VAULT_NAME, await this.DVM.methods._VAULT_().call())
await this.DVM.methods.setMaintainer(this.Maintainer).send(this.sendParam(this.Deployer))
console.log(log.blueText("[Init DVM context]")); console.log(log.blueText("[Init DVM context]"));
} }