118 lines
3.7 KiB
Solidity
118 lines
3.7 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))
|
|
*/
|
|
function _GeneralIntegrate(
|
|
uint256 V0,
|
|
uint256 V1,
|
|
uint256 V2,
|
|
uint256 i,
|
|
uint256 k
|
|
) internal pure returns (uint256) {
|
|
uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta
|
|
uint256 V0V1 = DecimalMath.divCeil(V0, V1); // V0/V1
|
|
uint256 V0V2 = DecimalMath.divCeil(V0, V2); // V0/V2
|
|
uint256 penalty = DecimalMath.mul(DecimalMath.mul(k, V0V1), V0V2); // k(V0^2/V1/V2)
|
|
return DecimalMath.mul(fairAmount, DecimalMath.ONE.sub(k).add(penalty));
|
|
}
|
|
|
|
/*
|
|
The same with 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
|
|
if deltaBSig=false, then Q2<Q1
|
|
*/
|
|
function _SolveQuadraticFunctionForTrade(
|
|
uint256 Q0,
|
|
uint256 Q1,
|
|
uint256 ideltaB,
|
|
bool deltaBSig,
|
|
uint256 k
|
|
) internal pure returns (uint256) {
|
|
// 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;
|
|
if (deltaBSig) {
|
|
b = b.add(ideltaB); // (1-k)Q1+i*deltaB
|
|
} else {
|
|
kQ02Q1 = kQ02Q1.add(ideltaB); // -i*(-deltaB)-kQ0^2/Q1
|
|
}
|
|
if (b >= kQ02Q1) {
|
|
b = b.sub(kQ02Q1);
|
|
minusbSig = true;
|
|
} else {
|
|
b = kQ02Q1.sub(b);
|
|
minusbSig = false;
|
|
}
|
|
|
|
// calculate sqrt
|
|
uint256 squareRoot = DecimalMath.mul(
|
|
DecimalMath.ONE.sub(k).mul(4),
|
|
DecimalMath.mul(k, Q0).mul(Q0)
|
|
); // 4(1-k)kQ0^2
|
|
squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b-4(1-k)kQ0*Q0)
|
|
|
|
// final res
|
|
uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k)
|
|
if (minusbSig) {
|
|
return DecimalMath.divFloor(b.add(squareRoot), denominator);
|
|
} else {
|
|
return DecimalMath.divFloor(squareRoot.sub(b), 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.divFloor(DecimalMath.mul(k, fairAmount), V1).mul(4);
|
|
sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt();
|
|
uint256 premium = DecimalMath.divFloor(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));
|
|
}
|
|
}
|