Files
dodo-contractV2/contracts/lib/DODOMath.sol

201 lines
5.9 KiB
Solidity
Raw Normal View History

2020-06-26 00:31:25 +08:00
/*
Copyright 2020 DODO ZOO.
SPDX-License-Identifier: Apache-2.0
*/
pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
import {SafeMath} from "./SafeMath.sol";
import {DecimalMath} from "./DecimalMath.sol";
/**
* @title DODOMath
* @author DODO Breeder
*
* @notice Functions for complex calculating. Including ONE Integration and TWO Quadratic solutions
*/
library DODOMath {
using SafeMath for uint256;
/*
2020-11-30 11:36:36 +08:00
Integrate dodo curve from V1 to V2
2020-06-26 00:31:25 +08:00
require V0>=V1>=V2>0
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))
2020-11-22 13:18:44 +08:00
2021-01-11 09:43:25 +08:00
i is the price of V-res trading pair
2020-11-22 13:18:44 +08:00
2020-11-30 11:59:55 +08:00
support k=1 & k=0 case
2020-11-22 13:18:44 +08:00
[round down]
2020-06-26 00:31:25 +08:00
*/
function _GeneralIntegrate(
uint256 V0,
uint256 V1,
uint256 V2,
uint256 i,
uint256 k
) internal pure returns (uint256) {
2020-11-18 17:51:50 +08:00
require(V0 > 0, "TARGET_IS_ZERO");
2020-11-22 13:18:44 +08:00
uint256 fairAmount = i.mul(V1.sub(V2)); // i*delta
2020-12-11 22:52:00 +08:00
if (k == 0) {
2020-12-21 23:16:09 +08:00
return fairAmount.div(DecimalMath.ONE);
2020-12-11 22:52:00 +08:00
}
2020-11-22 13:18:44 +08:00
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);
}
/*
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
2020-11-23 11:25:18 +08:00
give out target of V
2020-11-22 13:18:44 +08:00
2020-11-30 11:59:55 +08:00
support k=1 & k=0 case
2020-11-22 13:18:44 +08:00
[round down]
*/
function _SolveQuadraticFunctionForTarget(
uint256 V1,
uint256 delta,
uint256 i,
uint256 k
2020-11-30 11:59:55 +08:00
) internal pure returns (uint256) {
2021-01-13 20:39:41 +08:00
if (V1 == 0) {
return 0;
}
2020-11-30 11:59:55 +08:00
if (k == 0) {
return V1.add(DecimalMath.mulFloor(i, delta));
}
2020-11-22 13:18:44 +08:00
// V0 = V1*(1+(sqrt-1)/2k)
// sqrt = √(1+4kidelta/V1)
// premium = 1+(sqrt-1)/2k
2021-01-04 22:23:08 +08:00
// uint256 sqrt = (4 * k).mul(i).mul(delta).div(V1).add(DecimalMath.ONE2).sqrt();
uint256 sqrt;
uint256 ki = (4 * k).mul(i);
2021-01-11 09:43:25 +08:00
if (ki == 0) {
2021-01-04 22:23:08 +08:00
sqrt = DecimalMath.ONE;
2021-01-11 09:43:25 +08:00
} else if ((ki * delta) / ki == delta) {
2021-01-04 22:23:08 +08:00
sqrt = (ki * delta).div(V1).add(DecimalMath.ONE2).sqrt();
2021-01-11 09:43:25 +08:00
} else {
2021-01-07 21:58:24 +08:00
sqrt = ki.div(V1).mul(delta).add(DecimalMath.ONE2).sqrt();
2021-01-04 22:23:08 +08:00
}
2021-01-11 09:43:25 +08:00
uint256 premium =
DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k * 2).add(DecimalMath.ONE);
2020-11-22 13:18:44 +08:00
// V0 is greater than or equal to V1 according to the solution
2020-11-28 17:44:39 +08:00
return DecimalMath.mulFloor(V1, premium);
2020-06-26 00:31:25 +08:00
}
/*
2020-11-22 13:18:44 +08:00
Follow the integration expression above, we have:
2020-06-26 00:31:25 +08:00
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
2020-11-22 13:18:44 +08:00
c=-kQ0^2
2020-06-26 00:31:25 +08:00
and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k)
note: another root is negative, abondan
2020-11-22 13:18:44 +08:00
2020-11-20 19:55:32 +08:00
if deltaBSig=true, then Q2>Q1, user sell Q and receive B
if deltaBSig=false, then Q2<Q1, user sell B and receive Q
2020-11-06 16:03:18 +08:00
return |Q1-Q2|
2020-11-21 01:08:55 +08:00
2020-11-22 13:18:44 +08:00
as we only support sell amount as delta, the deltaB is always negative
the input ideltaB is actually -ideltaB in the equation
2020-11-21 01:08:55 +08:00
2020-11-22 13:18:44 +08:00
i is the price of delta-V trading pair
2020-11-30 11:59:55 +08:00
support k=1 & k=0 case
2020-11-22 13:18:44 +08:00
[round down]
2020-06-26 00:31:25 +08:00
*/
function _SolveQuadraticFunctionForTrade(
2020-11-22 13:18:44 +08:00
uint256 V0,
uint256 V1,
uint256 delta,
uint256 i,
2020-06-26 00:31:25 +08:00
uint256 k
) internal pure returns (uint256) {
2020-11-22 13:18:44 +08:00
require(V0 > 0, "TARGET_IS_ZERO");
2020-11-28 17:44:39 +08:00
if (delta == 0) {
return 0;
}
2020-11-30 11:59:55 +08:00
if (k == 0) {
2020-12-11 22:52:00 +08:00
return DecimalMath.mulFloor(i, delta) > V1 ? V1 : DecimalMath.mulFloor(i, delta);
2020-11-30 11:59:55 +08:00
}
2020-11-21 01:08:55 +08:00
if (k == DecimalMath.ONE) {
2020-11-22 13:18:44 +08:00
// if k==1
// Q2=Q1/(1+ideltaBQ1/Q0/Q0)
2020-12-09 19:21:20 +08:00
// temp = ideltaBQ1/Q0/Q0
2021-01-11 09:43:25 +08:00
// Q2 = Q1/(1+temp)
// Q1-Q2 = Q1*(1-1/(1+temp)) = Q1*(temp/(1+temp))
2021-01-04 22:23:08 +08:00
// uint256 temp = i.mul(delta).mul(V1).div(V0.mul(V0));
uint256 temp;
uint256 idelta = i.mul(delta);
2021-01-11 09:43:25 +08:00
if (idelta == 0) {
2021-01-04 22:23:08 +08:00
temp = 0;
2021-01-11 09:43:25 +08:00
} else if ((idelta * V1) / idelta == V1) {
2021-01-04 22:23:08 +08:00
temp = (idelta * V1).div(V0.mul(V0));
2021-01-11 09:43:25 +08:00
} else {
temp = delta.mul(V1).div(V0).mul(i).div(V0);
2021-01-04 22:23:08 +08:00
}
2020-11-22 13:18:44 +08:00
return V1.mul(temp).div(temp.add(DecimalMath.ONE));
2020-11-21 01:08:55 +08:00
}
2020-11-22 13:18:44 +08:00
2020-06-26 00:31:25 +08:00
// calculate -b value and sig
2020-11-23 11:25:18 +08:00
// b = kQ0^2/Q1-i*deltaB-(1-k)Q1
2020-11-22 13:18:44 +08:00
// part1 = (1-k)Q1 >=0
2020-11-23 11:25:18 +08:00
// part2 = kQ0^2/Q1-i*deltaB >=0
2020-11-22 13:18:44 +08:00
// 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 - part2;
2020-11-22 13:18:44 +08:00
bSig = false;
2020-06-26 00:31:25 +08:00
} else {
bAbs = part2 - bAbs;
2020-11-22 13:18:44 +08:00
bSig = true;
2020-06-26 00:31:25 +08:00
}
2020-11-22 13:18:44 +08:00
bAbs = bAbs.div(DecimalMath.ONE);
2020-06-26 00:31:25 +08:00
// calculate sqrt
2021-01-11 09:43:25 +08:00
uint256 squareRoot =
DecimalMath.mulFloor(
DecimalMath.ONE.sub(k).mul(4),
DecimalMath.mulFloor(k, V0).mul(V0)
); // 4(1-k)kQ0^2
2020-11-22 13:18:44 +08:00
squareRoot = bAbs.mul(bAbs).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0)
2020-06-26 00:31:25 +08:00
// final res
uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k)
2020-07-10 13:32:20 +08:00
uint256 numerator;
2020-11-22 13:18:44 +08:00
if (bSig) {
numerator = squareRoot.sub(bAbs);
2020-06-26 00:31:25 +08:00
} else {
2020-11-22 13:18:44 +08:00
numerator = bAbs.add(squareRoot);
2020-07-10 13:32:20 +08:00
}
uint256 V2 = DecimalMath.divCeil(numerator, denominator);
if (V2 > V1) {
return 0;
} else {
return V1 - V2;
}
2020-06-26 00:31:25 +08:00
}
}