refactor DODOMath
This commit is contained in:
@@ -151,54 +151,6 @@ contract DVMTrader is DVMVault {
|
||||
return (receiveBaseAmount, mtFee);
|
||||
}
|
||||
|
||||
// // 这是一个仅供查询的合约,所有交易都是基于先给input,再输出output的
|
||||
// // 所以想要买10ETH,这个函数可以给你一个大概的成本,你用这个成本输入,最后能否得到10ETH是要看情况的
|
||||
// function queryBuyBase(address trader, uint256 receiveBaseAmount)
|
||||
// public
|
||||
// view
|
||||
// returns (uint256 payQuoteAmount)
|
||||
// {
|
||||
// uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
|
||||
// uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader);
|
||||
// uint256 validReceiveBaseAmount = DecimalMath.divCeil(
|
||||
// receiveBaseAmount,
|
||||
// DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate)
|
||||
// );
|
||||
// (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve();
|
||||
// require(baseReserve > validReceiveBaseAmount, "DODO_BASE_BALANCE_NOT_ENOUGH");
|
||||
|
||||
// uint256 B0 = calculateBase0(baseReserve, quoteReserve);
|
||||
// uint256 B2 = baseReserve.sub(validReceiveBaseAmount);
|
||||
// payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_);
|
||||
// return payQuoteAmount;
|
||||
// }
|
||||
|
||||
// function queryBuyQuote(address trader, uint256 receiveQuoteAmount)
|
||||
// public
|
||||
// view
|
||||
// returns (uint256 payBaseAmount)
|
||||
// {
|
||||
// uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
|
||||
// uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader);
|
||||
// uint256 validReceiveQuoteAmount = DecimalMath.divCeil(
|
||||
// receiveQuoteAmount,
|
||||
// DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate)
|
||||
// );
|
||||
// (uint256 baseReserve, uint256 quoteReserve) = getVaultReserve();
|
||||
// require(quoteReserve > validReceiveQuoteAmount, "DODO_QUOTE_BALANCE_NOT_ENOUGH");
|
||||
|
||||
// uint256 B0 = calculateBase0(baseReserve, quoteReserve);
|
||||
// uint256 fairAmount = DecimalMath.divFloor(validReceiveQuoteAmount, _I_);
|
||||
// payBaseAmount = DODOMath._SolveQuadraticFunctionForTrade(
|
||||
// B0,
|
||||
// baseReserve,
|
||||
// fairAmount,
|
||||
// true,
|
||||
// _K_
|
||||
// );
|
||||
// return payBaseAmount;
|
||||
// }
|
||||
|
||||
function getMidPrice() public view returns (uint256 midPrice) {
|
||||
return PMMPricing.getMidPrice(getPMMState());
|
||||
}
|
||||
@@ -217,13 +169,23 @@ contract DVMTrader is DVMVault {
|
||||
}
|
||||
|
||||
function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) {
|
||||
uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_);
|
||||
return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount);
|
||||
return
|
||||
DODOMath._SolveQuadraticFunctionForTarget(
|
||||
baseAmount,
|
||||
quoteAmount,
|
||||
DecimalMath.reciprocalFloor(_I_),
|
||||
_K_
|
||||
);
|
||||
}
|
||||
|
||||
function getBase0() public view returns (uint256) {
|
||||
(uint256 baseAmount, uint256 quoteAmount) = getVaultReserve();
|
||||
uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_);
|
||||
return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount);
|
||||
return
|
||||
DODOMath._SolveQuadraticFunctionForTarget(
|
||||
baseAmount,
|
||||
quoteAmount,
|
||||
DecimalMath.reciprocalFloor(_I_),
|
||||
_K_
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ library DODOMath {
|
||||
res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1)
|
||||
let V1-V2=delta
|
||||
res = i*delta*(1-k+k(V0^2/V1/V2))
|
||||
|
||||
i is the price of res-V trading pair
|
||||
|
||||
[round down]
|
||||
*/
|
||||
function _GeneralIntegrate(
|
||||
uint256 V0,
|
||||
@@ -35,94 +39,114 @@ library DODOMath {
|
||||
uint256 k
|
||||
) internal pure returns (uint256) {
|
||||
require(V0 > 0, "TARGET_IS_ZERO");
|
||||
uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta
|
||||
uint256 V0V0V1V2 = DecimalMath.divCeil(V0.mul(V0).div(V1), V2);
|
||||
uint256 penalty = DecimalMath.mul(k, V0V0V1V2); // k(V0^2/V1/V2)
|
||||
return DecimalMath.mul(fairAmount, DecimalMath.ONE.sub(k).add(penalty));
|
||||
uint256 fairAmount = i.mul(V1.sub(V2)); // i*delta
|
||||
uint256 V0V0V1V2 = DecimalMath.divFloor(V0.mul(V0).div(V1), V2);
|
||||
uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2); // k(V0^2/V1/V2)
|
||||
return DecimalMath.ONE.sub(k).add(penalty).mul(fairAmount).div(DecimalMath.ONE2);
|
||||
}
|
||||
|
||||
/*
|
||||
The same with integration expression above, we have:
|
||||
Follow the integration function above
|
||||
i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
|
||||
Assume Q2=Q0, Given Q1 and deltaB, solve Q0
|
||||
|
||||
i is the price of delta-V trading pair
|
||||
|
||||
[round down]
|
||||
*/
|
||||
function _SolveQuadraticFunctionForTarget(
|
||||
uint256 V1,
|
||||
uint256 delta,
|
||||
uint256 i,
|
||||
uint256 k
|
||||
) internal pure returns (uint256 V0) {
|
||||
// V0 = V1*(1+(sqrt-1)/2k)
|
||||
// sqrt = √(1+4kidelta/V1)
|
||||
// premium = 1+(sqrt-1)/2k
|
||||
uint256 sqrt = (4 * k).mul(i).mul(delta).div(V1).add(DecimalMath.ONE2).sqrt();
|
||||
uint256 premium = DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k * 2).add(
|
||||
DecimalMath.ONE
|
||||
);
|
||||
// V0 is greater than or equal to V1 according to the solution
|
||||
return DecimalMath.mul(V1, DecimalMath.ONE.add(premium));
|
||||
}
|
||||
|
||||
/*
|
||||
Follow the integration expression above, we have:
|
||||
i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
|
||||
Given Q1 and deltaB, solve Q2
|
||||
This is a quadratic function and the standard version is
|
||||
aQ2^2 + bQ2 + c = 0, where
|
||||
a=1-k
|
||||
-b=(1-k)Q1-kQ0^2/Q1+i*deltaB
|
||||
c=-kQ0^2
|
||||
c=-kQ0^2
|
||||
and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k)
|
||||
note: another root is negative, abondan
|
||||
|
||||
if deltaBSig=true, then Q2>Q1, user sell Q and receive B
|
||||
if deltaBSig=false, then Q2<Q1, user sell B and receive Q
|
||||
return |Q1-Q2|
|
||||
|
||||
if k==1
|
||||
Q2 = -c/b
|
||||
as we only support sell amount as delta, the deltaB is always negative
|
||||
the input ideltaB is actually -ideltaB in the equation
|
||||
|
||||
if k==0
|
||||
i is the price of delta-V trading pair
|
||||
|
||||
[round down]
|
||||
*/
|
||||
function _SolveQuadraticFunctionForTrade(
|
||||
uint256 Q0,
|
||||
uint256 Q1,
|
||||
uint256 ideltaB,
|
||||
// bool deltaBSig, deltaBSig is always false
|
||||
uint256 V0,
|
||||
uint256 V1,
|
||||
uint256 delta,
|
||||
uint256 i,
|
||||
uint256 k
|
||||
) internal pure returns (uint256) {
|
||||
require(Q0 > 0, "TARGET_IS_ZERO");
|
||||
require(V0 > 0, "TARGET_IS_ZERO");
|
||||
if (k == DecimalMath.ONE) {
|
||||
// Q2=Q1/(1-ideltaBQ1/Q0/Q0)
|
||||
uint256 temp = ideltaB.mul(Q1).mul(DecimalMath.ONE).div(Q0.mul(Q0));
|
||||
return Q1.sub(DecimalMath.divFloor(DecimalMath.ONE, DecimalMath.ONE.add(temp)));
|
||||
// if k==1
|
||||
// Q2=Q1/(1+ideltaBQ1/Q0/Q0)
|
||||
// temp = (1+ideltaBQ1/Q0/Q0)
|
||||
// Q1-Q2 = Q1*(temp/(1+temp))
|
||||
uint256 temp = i.mul(delta).mul(V1).div(V0.mul(V0));
|
||||
return V1.mul(temp).div(temp.add(DecimalMath.ONE));
|
||||
}
|
||||
|
||||
// calculate -b value and sig
|
||||
// -b = (1-k)Q1-kQ0^2/Q1+i*deltaB
|
||||
uint256 kQ02Q1 = DecimalMath.mul(k, Q0).mul(Q0).div(Q1); // kQ0^2/Q1
|
||||
uint256 b = DecimalMath.mul(DecimalMath.ONE.sub(k), Q1); // (1-k)Q1
|
||||
bool minusbSig = true;
|
||||
kQ02Q1 = kQ02Q1.add(ideltaB); // i*deltaB+kQ0^2/Q1
|
||||
if (b >= kQ02Q1) {
|
||||
b = b.sub(kQ02Q1);
|
||||
minusbSig = true;
|
||||
// part1 = (1-k)Q1 >=0
|
||||
// part2 = -i*deltaB+kQ0^2/Q1 >=0
|
||||
// bAbs = abs(part1-part2)
|
||||
// if part1>part2 => b is negative => bSig is false
|
||||
// if part2>part1 => b is positive => bSig is true
|
||||
uint256 part2 = k.mul(V0).div(V1).mul(V0).add(i.mul(delta)); // kQ0^2/Q1-i*deltaB
|
||||
uint256 bAbs = DecimalMath.ONE.sub(k).mul(V1); // (1-k)Q1
|
||||
|
||||
bool bSig;
|
||||
if (bAbs >= part2) {
|
||||
bAbs = bAbs.sub(part2);
|
||||
bSig = false;
|
||||
} else {
|
||||
b = kQ02Q1.sub(b);
|
||||
minusbSig = false;
|
||||
bAbs = part2.sub(bAbs);
|
||||
bSig = true;
|
||||
}
|
||||
bAbs = bAbs.div(DecimalMath.ONE);
|
||||
|
||||
// calculate sqrt
|
||||
uint256 squareRoot = DecimalMath.mul(
|
||||
DecimalMath.ONE.sub(k).mul(4),
|
||||
DecimalMath.mul(k, Q0).mul(Q0)
|
||||
DecimalMath.mul(k, V0).mul(V0)
|
||||
); // 4(1-k)kQ0^2
|
||||
squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0)
|
||||
squareRoot = bAbs.mul(bAbs).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0)
|
||||
|
||||
// final res
|
||||
uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k)
|
||||
uint256 numerator;
|
||||
if (minusbSig) {
|
||||
numerator = b.add(squareRoot);
|
||||
if (bSig) {
|
||||
numerator = squareRoot.sub(bAbs);
|
||||
} else {
|
||||
numerator = squareRoot.sub(b);
|
||||
numerator = bAbs.add(squareRoot);
|
||||
}
|
||||
|
||||
return Q1.sub(DecimalMath.divCeil(numerator, denominator));
|
||||
}
|
||||
|
||||
/*
|
||||
Start from the integration function
|
||||
i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
|
||||
Assume Q2=Q0, Given Q1 and deltaB, solve Q0
|
||||
let fairAmount = i*deltaB
|
||||
*/
|
||||
function _SolveQuadraticFunctionForTarget(
|
||||
uint256 V1,
|
||||
uint256 k,
|
||||
uint256 fairAmount
|
||||
) internal pure returns (uint256 V0) {
|
||||
// V0 = V1+V1*(sqrt-1)/2k
|
||||
uint256 sqrt = DecimalMath.divCeil(DecimalMath.mul(k, fairAmount).mul(4), V1);
|
||||
sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt();
|
||||
uint256 premium = DecimalMath.divCeil(sqrt.sub(DecimalMath.ONE), k.mul(2));
|
||||
// V0 is greater than or equal to V1 according to the solution
|
||||
return DecimalMath.mul(V1, DecimalMath.ONE.add(premium));
|
||||
return V1.sub(DecimalMath.divCeil(numerator, denominator));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import {SafeMath} from "./SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title DecimalMath
|
||||
* @author DODO Breeder
|
||||
@@ -21,24 +20,33 @@ library DecimalMath {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 constant ONE = 10**18;
|
||||
uint256 constant ONE2 = 10**36;
|
||||
|
||||
function mul(uint256 target, uint256 d) internal pure returns (uint256) {
|
||||
return target.mul(d) / ONE;
|
||||
return target.mul(d) / (10**18);
|
||||
}
|
||||
|
||||
function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) {
|
||||
return target.mul(d) / ONE;
|
||||
return target.mul(d) / (10**18);
|
||||
}
|
||||
|
||||
function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) {
|
||||
return target.mul(d).divCeil(ONE);
|
||||
return target.mul(d).divCeil(10**18);
|
||||
}
|
||||
|
||||
function divFloor(uint256 target, uint256 d) internal pure returns (uint256) {
|
||||
return target.mul(ONE).div(d);
|
||||
return target.mul(10**18).div(d);
|
||||
}
|
||||
|
||||
function divCeil(uint256 target, uint256 d) internal pure returns (uint256) {
|
||||
return target.mul(ONE).divCeil(d);
|
||||
return target.mul(10**18).divCeil(d);
|
||||
}
|
||||
|
||||
function reciprocalFloor(uint256 target) internal pure returns (uint256) {
|
||||
return uint256(10**36).div(target);
|
||||
}
|
||||
|
||||
function reciprocalCeil(uint256 target) internal pure returns (uint256) {
|
||||
return uint256(10**36).divCeil(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ library PMMPricing {
|
||||
DODOMath._SolveQuadraticFunctionForTrade(
|
||||
state.Q0,
|
||||
state.Q0,
|
||||
DecimalMath.mulFloor(state.i, payBaseAmount),
|
||||
payBaseAmount,
|
||||
state.i,
|
||||
state.K
|
||||
);
|
||||
}
|
||||
@@ -140,7 +141,8 @@ library PMMPricing {
|
||||
DODOMath._SolveQuadraticFunctionForTrade(
|
||||
state.B0,
|
||||
state.B0,
|
||||
DecimalMath.divFloor(payQuoteAmount, state.i),
|
||||
payQuoteAmount,
|
||||
DecimalMath.reciprocalFloor(state.i),
|
||||
state.K
|
||||
);
|
||||
}
|
||||
@@ -157,7 +159,7 @@ library PMMPricing {
|
||||
state.Q0,
|
||||
state.Q.add(payQuoteAmount),
|
||||
state.Q,
|
||||
DecimalMath.divFloor(DecimalMath.ONE, state.i),
|
||||
DecimalMath.reciprocalFloor(state.i),
|
||||
state.K
|
||||
);
|
||||
}
|
||||
@@ -171,7 +173,8 @@ library PMMPricing {
|
||||
DODOMath._SolveQuadraticFunctionForTrade(
|
||||
state.Q0,
|
||||
state.Q,
|
||||
DecimalMath.mul(state.i, payBaseAmount),
|
||||
payBaseAmount,
|
||||
state.i,
|
||||
state.K
|
||||
);
|
||||
}
|
||||
@@ -202,7 +205,8 @@ library PMMPricing {
|
||||
DODOMath._SolveQuadraticFunctionForTrade(
|
||||
state.B0,
|
||||
state.B,
|
||||
DecimalMath.divFloor(payQuoteAmount, state.i),
|
||||
payQuoteAmount,
|
||||
DecimalMath.reciprocalFloor(state.i),
|
||||
state.K
|
||||
);
|
||||
}
|
||||
@@ -212,11 +216,19 @@ library PMMPricing {
|
||||
// todo 我不确定这个函数是不是能改state的状态
|
||||
function adjustedTarget(PMMState memory state) internal pure {
|
||||
if (state.R == RState.BELOW_ONE) {
|
||||
uint256 fairAmount = DecimalMath.mulFloor(state.B.sub(state.B0), state.i);
|
||||
state.Q0 = DODOMath._SolveQuadraticFunctionForTarget(state.B, state.K, fairAmount);
|
||||
state.Q0 = DODOMath._SolveQuadraticFunctionForTarget(
|
||||
state.B,
|
||||
state.B.sub(state.B0),
|
||||
state.i,
|
||||
state.K
|
||||
);
|
||||
} else if (state.R == RState.ABOVE_ONE) {
|
||||
uint256 fairAmount = DecimalMath.divFloor(state.Q.sub(state.Q0), state.i);
|
||||
state.B0 = DODOMath._SolveQuadraticFunctionForTarget(state.Q, state.K, fairAmount);
|
||||
state.B0 = DODOMath._SolveQuadraticFunctionForTarget(
|
||||
state.Q,
|
||||
state.Q.sub(state.Q0),
|
||||
DecimalMath.reciprocalFloor(state.i),
|
||||
state.K
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user