/* 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= 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)); } }