154 lines
4.6 KiB
Solidity
154 lines
4.6 KiB
Solidity
/*
|
|
|
|
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;
|
|
|
|
/*
|
|
Integrate dodo curve fron V1 to V2
|
|
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))
|
|
|
|
i is the price of res-V trading pair
|
|
|
|
[round down]
|
|
*/
|
|
function _GeneralIntegrate(
|
|
uint256 V0,
|
|
uint256 V1,
|
|
uint256 V2,
|
|
uint256 i,
|
|
uint256 k
|
|
) internal pure returns (uint256) {
|
|
require(V0 > 0, "TARGET_IS_ZERO");
|
|
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);
|
|
}
|
|
|
|
/*
|
|
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
|
|
give out target of V
|
|
|
|
[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, 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
|
|
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|
|
|
|
|
as we only support sell amount as delta, the deltaB is always negative
|
|
the input ideltaB is actually -ideltaB in the equation
|
|
|
|
i is the price of delta-V trading pair
|
|
|
|
[round down]
|
|
*/
|
|
function _SolveQuadraticFunctionForTrade(
|
|
uint256 V0,
|
|
uint256 V1,
|
|
uint256 delta,
|
|
uint256 i,
|
|
uint256 k
|
|
) internal pure returns (uint256) {
|
|
require(V0 > 0, "TARGET_IS_ZERO");
|
|
if (k == DecimalMath.ONE) {
|
|
// 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 = kQ0^2/Q1-i*deltaB-(1-k)Q1
|
|
// part1 = (1-k)Q1 >=0
|
|
// part2 = kQ0^2/Q1-i*deltaB >=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 {
|
|
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, V0).mul(V0)
|
|
); // 4(1-k)kQ0^2
|
|
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 (bSig) {
|
|
numerator = squareRoot.sub(bAbs);
|
|
} else {
|
|
numerator = bAbs.add(squareRoot);
|
|
}
|
|
|
|
return V1.sub(DecimalMath.divCeil(numerator, denominator));
|
|
}
|
|
}
|