Skip to content

Instantly share code, notes, and snippets.

@gititGoro
Last active December 31, 2020 03:36
Show Gist options
  • Save gititGoro/0518371983fbb6ded6bfe88cafcafcc3 to your computer and use it in GitHub Desktop.
Save gititGoro/0518371983fbb6ded6bfe88cafcafcc3 to your computer and use it in GitHub Desktop.
using ABDK's quad precision floating point library for solidity to calculate the Lock percentage for Rock3t. Alpha assumed at 1 to save gas.
pragma solidity 0.7.1;
abstract contract UniswapV2Router02 {
address public WETH;
function quote(uint amountA, uint reserveA, uint reserveB) public virtual pure returns (uint);
}
abstract contract TokenPair {
function getReserves() public virtual view returns (uint,uint, uint32);
}
// SPDX-License-Identifier: BSD-4-Clause
/*
* ABDK Math Quad Smart Contract Library. Copyright © 2019 by ABDK Consulting.
* Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>
*/
/**
* Smart contract library of mathematical functions operating with IEEE 754
* quadruple-precision binary floating-point numbers (quadruple precision
* numbers). As long as quadruple precision numbers are 16-bytes long, they are
* represented by bytes16 type.
*/
library ABDKMathQuad {
/*
* 0.
*/
bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000;
/*
* -0.
*/
bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000;
/*
* +Infinity.
*/
bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000;
/*
* -Infinity.
*/
bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000;
/*
* Canonical NaN value.
*/
bytes16 private constant NaN = 0x7FFF8000000000000000000000000000;
/**
* Convert signed 256-bit integer number into quadruple precision number.
*
* @param x signed 256-bit integer number
* @return quadruple precision number
*/
function fromInt (int256 x) internal pure returns (bytes16) {
if (x == 0) return bytes16 (0);
else {
// We rely on overflow behavior here
uint256 result = uint256 (x > 0 ? x : -x);
uint256 msb = msb (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112;
if (x < 0) result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
/**
* Convert quadruple precision number into signed 256-bit integer number
* rounding towards zero. Revert on overflow.
*
* @param x quadruple precision number
* @return signed 256-bit integer number
*/
function toInt (bytes16 x) internal pure returns (int256) {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
require (exponent <= 16638); // Overflow
if (exponent < 16383) return 0; // Underflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16495) result >>= 16495 - exponent;
else if (exponent > 16495) result <<= exponent - 16495;
if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000);
return -int256 (result); // We rely on overflow behavior here
} else {
require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int256 (result);
}
}
/**
* Convert unsigned 256-bit integer number into quadruple precision number.
*
* @param x unsigned 256-bit integer number
* @return quadruple precision number
*/
function fromUInt (uint256 x) internal pure returns (bytes16) {
if (x == 0) return bytes16 (0);
else {
uint256 result = x;
uint256 msb = msb (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112;
return bytes16 (uint128 (result));
}
}
/**
* Convert quadruple precision number into unsigned 256-bit integer number
* rounding towards zero. Revert on underflow. Note, that negative floating
* point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer
* without error, because they are rounded to zero.
*
* @param x quadruple precision number
* @return unsigned 256-bit integer number
*/
function toUInt (bytes16 x) internal pure returns (uint256) {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
if (exponent < 16383) return 0; // Underflow
require (uint128 (x) < 0x80000000000000000000000000000000); // Negative
require (exponent <= 16638); // Overflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16495) result >>= 16495 - exponent;
else if (exponent > 16495) result <<= exponent - 16495;
return result;
}
/**
* Convert signed 128.128 bit fixed point number into quadruple precision
* number.
*
* @param x signed 128.128 bit fixed point number
* @return quadruple precision number
*/
function from128x128 (int256 x) internal pure returns (bytes16) {
if (x == 0) return bytes16 (0);
else {
// We rely on overflow behavior here
uint256 result = uint256 (x > 0 ? x : -x);
uint256 msb = msb (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16255 + msb << 112;
if (x < 0) result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
/**
* Convert quadruple precision number into signed 128.128 bit fixed point
* number. Revert on overflow.
*
* @param x quadruple precision number
* @return signed 128.128 bit fixed point number
*/
function to128x128 (bytes16 x) internal pure returns (int256) {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
require (exponent <= 16510); // Overflow
if (exponent < 16255) return 0; // Underflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16367) result >>= 16367 - exponent;
else if (exponent > 16367) result <<= exponent - 16367;
if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000);
return -int256 (result); // We rely on overflow behavior here
} else {
require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int256 (result);
}
}
/**
* Convert signed 64.64 bit fixed point number into quadruple precision
* number.
*
* @param x signed 64.64 bit fixed point number
* @return quadruple precision number
*/
function from64x64 (int128 x) internal pure returns (bytes16) {
if (x == 0) return bytes16 (0);
else {
// We rely on overflow behavior here
uint256 result = uint128 (x > 0 ? x : -x);
uint256 msb = msb (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16319 + msb << 112;
if (x < 0) result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
/**
* Convert quadruple precision number into signed 64.64 bit fixed point
* number. Revert on overflow.
*
* @param x quadruple precision number
* @return signed 64.64 bit fixed point number
*/
function to64x64 (bytes16 x) internal pure returns (int128) {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
require (exponent <= 16446); // Overflow
if (exponent < 16319) return 0; // Underflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16431) result >>= 16431 - exponent;
else if (exponent > 16431) result <<= exponent - 16431;
if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
require (result <= 0x80000000000000000000000000000000);
return -int128 (result); // We rely on overflow behavior here
} else {
require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int128 (result);
}
}
/**
* Convert octuple precision number into quadruple precision number.
*
* @param x octuple precision number
* @return quadruple precision number
*/
function fromOctuple (bytes32 x) internal pure returns (bytes16) {
bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0;
uint256 exponent = uint256 (x) >> 236 & 0x7FFFF;
uint256 significand = uint256 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (exponent == 0x7FFFF) {
if (significand > 0) return NaN;
else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
}
if (exponent > 278526)
return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
else if (exponent < 245649)
return negative ? NEGATIVE_ZERO : POSITIVE_ZERO;
else if (exponent < 245761) {
significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> 245885 - exponent;
exponent = 0;
} else {
significand >>= 124;
exponent -= 245760;
}
uint128 result = uint128 (significand | exponent << 112);
if (negative) result |= 0x80000000000000000000000000000000;
return bytes16 (result);
}
/**
* Convert quadruple precision number into octuple precision number.
*
* @param x quadruple precision number
* @return octuple precision number
*/
function toOctuple (bytes16 x) internal pure returns (bytes32) {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
uint256 result = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN
else if (exponent == 0) {
if (result > 0) {
uint256 msb = msb (result);
result = result << 236 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
exponent = 245649 + msb;
}
} else {
result <<= 124;
exponent += 245760;
}
result |= exponent << 236;
if (uint128 (x) >= 0x80000000000000000000000000000000)
result |= 0x8000000000000000000000000000000000000000000000000000000000000000;
return bytes32 (result);
}
/**
* Convert double precision number into quadruple precision number.
*
* @param x double precision number
* @return quadruple precision number
*/
function fromDouble (bytes8 x) internal pure returns (bytes16) {
uint256 exponent = uint64 (x) >> 52 & 0x7FF;
uint256 result = uint64 (x) & 0xFFFFFFFFFFFFF;
if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN
else if (exponent == 0) {
if (result > 0) {
uint256 msb = msb (result);
result = result << 112 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
exponent = 15309 + msb;
}
} else {
result <<= 60;
exponent += 15360;
}
result |= exponent << 112;
if (x & 0x8000000000000000 > 0)
result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
/**
* Convert quadruple precision number into double precision number.
*
* @param x quadruple precision number
* @return double precision number
*/
function toDouble (bytes16 x) internal pure returns (bytes8) {
bool negative = uint128 (x) >= 0x80000000000000000000000000000000;
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
uint256 significand = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (exponent == 0x7FFF) {
if (significand > 0) return 0x7FF8000000000000; // NaN
else return negative ?
bytes8 (0xFFF0000000000000) : // -Infinity
bytes8 (0x7FF0000000000000); // Infinity
}
if (exponent > 17406)
return negative ?
bytes8 (0xFFF0000000000000) : // -Infinity
bytes8 (0x7FF0000000000000); // Infinity
else if (exponent < 15309)
return negative ?
bytes8 (0x8000000000000000) : // -0
bytes8 (0x0000000000000000); // 0
else if (exponent < 15361) {
significand = (significand | 0x10000000000000000000000000000) >> 15421 - exponent;
exponent = 0;
} else {
significand >>= 60;
exponent -= 15360;
}
uint64 result = uint64 (significand | exponent << 52);
if (negative) result |= 0x8000000000000000;
return bytes8 (result);
}
/**
* Test whether given quadruple precision number is NaN.
*
* @param x quadruple precision number
* @return true if x is NaN, false otherwise
*/
function isNaN (bytes16 x) internal pure returns (bool) {
return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF >
0x7FFF0000000000000000000000000000;
}
/**
* Test whether given quadruple precision number is positive or negative
* infinity.
*
* @param x quadruple precision number
* @return true if x is positive or negative infinity, false otherwise
*/
function isInfinity (bytes16 x) internal pure returns (bool) {
return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ==
0x7FFF0000000000000000000000000000;
}
/**
* Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x
* is positive. Note that sign (-0) is zero. Revert if x is NaN.
*
* @param x quadruple precision number
* @return sign of x
*/
function sign (bytes16 x) internal pure returns (int8) {
uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN
if (absoluteX == 0) return 0;
else if (uint128 (x) >= 0x80000000000000000000000000000000) return -1;
else return 1;
}
/**
* Calculate sign (x - y). Revert if either argument is NaN, or both
* arguments are infinities of the same sign.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return sign (x - y)
*/
function cmp (bytes16 x, bytes16 y) internal pure returns (int8) {
uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN
uint128 absoluteY = uint128 (y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
require (absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN
// Not infinities of the same sign
require (x != y || absoluteX < 0x7FFF0000000000000000000000000000);
if (x == y) return 0;
else {
bool negativeX = uint128 (x) >= 0x80000000000000000000000000000000;
bool negativeY = uint128 (y) >= 0x80000000000000000000000000000000;
if (negativeX) {
if (negativeY) return absoluteX > absoluteY ? -1 : int8 (1);
else return -1;
} else {
if (negativeY) return 1;
else return absoluteX > absoluteY ? int8 (1) : -1;
}
}
}
/**
* Test whether x equals y. NaN, infinity, and -infinity are not equal to
* anything.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return true if x equals to y, false otherwise
*/
function eq (bytes16 x, bytes16 y) internal pure returns (bool) {
if (x == y) {
return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF <
0x7FFF0000000000000000000000000000;
} else return false;
}
/**
* Calculate x + y. Special values behave in the following way:
*
* NaN + x = NaN for any x.
* Infinity + x = Infinity for any finite x.
* -Infinity + x = -Infinity for any finite x.
* Infinity + Infinity = Infinity.
* -Infinity + -Infinity = -Infinity.
* Infinity + -Infinity = -Infinity + Infinity = NaN.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function add (bytes16 x, bytes16 y) internal pure returns (bytes16) {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) {
if (yExponent == 0x7FFF) {
if (x == y) return x;
else return NaN;
} else return x;
} else if (yExponent == 0x7FFF) return y;
else {
bool xSign = uint128 (x) >= 0x80000000000000000000000000000000;
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
bool ySign = uint128 (y) >= 0x80000000000000000000000000000000;
uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (yExponent == 0) yExponent = 1;
else ySignifier |= 0x10000000000000000000000000000;
if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y;
else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x;
else {
int256 delta = int256 (xExponent) - int256 (yExponent);
if (xSign == ySign) {
if (delta > 112) return x;
else if (delta > 0) ySignifier >>= uint256 (delta);
else if (delta < -112) return y;
else if (delta < 0) {
xSignifier >>= uint256 (-delta);
xExponent = yExponent;
}
xSignifier += ySignifier;
if (xSignifier >= 0x20000000000000000000000000000) {
xSignifier >>= 1;
xExponent += 1;
}
if (xExponent == 0x7FFF)
return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
else {
if (xSignifier < 0x10000000000000000000000000000) xExponent = 0;
else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
return bytes16 (uint128 (
(xSign ? 0x80000000000000000000000000000000 : 0) |
(xExponent << 112) |
xSignifier));
}
} else {
if (delta > 0) {
xSignifier <<= 1;
xExponent -= 1;
} else if (delta < 0) {
ySignifier <<= 1;
xExponent = yExponent - 1;
}
if (delta > 112) ySignifier = 1;
else if (delta > 1) ySignifier = (ySignifier - 1 >> uint256 (delta - 1)) + 1;
else if (delta < -112) xSignifier = 1;
else if (delta < -1) xSignifier = (xSignifier - 1 >> uint256 (-delta - 1)) + 1;
if (xSignifier >= ySignifier) xSignifier -= ySignifier;
else {
xSignifier = ySignifier - xSignifier;
xSign = ySign;
}
if (xSignifier == 0)
return POSITIVE_ZERO;
uint256 msb = msb (xSignifier);
if (msb == 113) {
xSignifier = xSignifier >> 1 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent += 1;
} else if (msb < 112) {
uint256 shift = 112 - msb;
if (xExponent > shift) {
xSignifier = xSignifier << shift & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent -= shift;
} else {
xSignifier <<= xExponent - 1;
xExponent = 0;
}
} else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0x7FFF)
return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
else return bytes16 (uint128 (
(xSign ? 0x80000000000000000000000000000000 : 0) |
(xExponent << 112) |
xSignifier));
}
}
}
}
/**
* Calculate x - y. Special values behave in the following way:
*
* NaN - x = NaN for any x.
* Infinity - x = Infinity for any finite x.
* -Infinity - x = -Infinity for any finite x.
* Infinity - -Infinity = Infinity.
* -Infinity - Infinity = -Infinity.
* Infinity - Infinity = -Infinity - -Infinity = NaN.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function sub (bytes16 x, bytes16 y) internal pure returns (bytes16) {
return add (x, y ^ 0x80000000000000000000000000000000);
}
/**
* Calculate x * y. Special values behave in the following way:
*
* NaN * x = NaN for any x.
* Infinity * x = Infinity for any finite positive x.
* Infinity * x = -Infinity for any finite negative x.
* -Infinity * x = -Infinity for any finite positive x.
* -Infinity * x = Infinity for any finite negative x.
* Infinity * 0 = NaN.
* -Infinity * 0 = NaN.
* Infinity * Infinity = Infinity.
* Infinity * -Infinity = -Infinity.
* -Infinity * Infinity = -Infinity.
* -Infinity * -Infinity = Infinity.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function mul (bytes16 x, bytes16 y) internal pure returns (bytes16) {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) {
if (yExponent == 0x7FFF) {
if (x == y) return x ^ y & 0x80000000000000000000000000000000;
else if (x ^ y == 0x80000000000000000000000000000000) return x | y;
else return NaN;
} else {
if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
else return x ^ y & 0x80000000000000000000000000000000;
}
} else if (yExponent == 0x7FFF) {
if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
else return y ^ x & 0x80000000000000000000000000000000;
} else {
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (yExponent == 0) yExponent = 1;
else ySignifier |= 0x10000000000000000000000000000;
xSignifier *= ySignifier;
if (xSignifier == 0)
return (x ^ y) & 0x80000000000000000000000000000000 > 0 ?
NEGATIVE_ZERO : POSITIVE_ZERO;
xExponent += yExponent;
uint256 msb =
xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 :
xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 :
msb (xSignifier);
if (xExponent + msb < 16496) { // Underflow
xExponent = 0;
xSignifier = 0;
} else if (xExponent + msb < 16608) { // Subnormal
if (xExponent < 16496)
xSignifier >>= 16496 - xExponent;
else if (xExponent > 16496)
xSignifier <<= xExponent - 16496;
xExponent = 0;
} else if (xExponent + msb > 49373) {
xExponent = 0x7FFF;
xSignifier = 0;
} else {
if (msb > 112)
xSignifier >>= msb - 112;
else if (msb < 112)
xSignifier <<= 112 - msb;
xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent = xExponent + msb - 16607;
}
return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) |
xExponent << 112 | xSignifier));
}
}
/**
* Calculate x / y. Special values behave in the following way:
*
* NaN / x = NaN for any x.
* x / NaN = NaN for any x.
* Infinity / x = Infinity for any finite non-negative x.
* Infinity / x = -Infinity for any finite negative x including -0.
* -Infinity / x = -Infinity for any finite non-negative x.
* -Infinity / x = Infinity for any finite negative x including -0.
* x / Infinity = 0 for any finite non-negative x.
* x / -Infinity = -0 for any finite non-negative x.
* x / Infinity = -0 for any finite non-negative x including -0.
* x / -Infinity = 0 for any finite non-negative x including -0.
*
* Infinity / Infinity = NaN.
* Infinity / -Infinity = -NaN.
* -Infinity / Infinity = -NaN.
* -Infinity / -Infinity = NaN.
*
* Division by zero behaves in the following way:
*
* x / 0 = Infinity for any finite positive x.
* x / -0 = -Infinity for any finite positive x.
* x / 0 = -Infinity for any finite negative x.
* x / -0 = Infinity for any finite negative x.
* 0 / 0 = NaN.
* 0 / -0 = NaN.
* -0 / 0 = NaN.
* -0 / -0 = NaN.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function div (bytes16 x, bytes16 y) internal pure returns (bytes16) {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) {
if (yExponent == 0x7FFF) return NaN;
else return x ^ y & 0x80000000000000000000000000000000;
} else if (yExponent == 0x7FFF) {
if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN;
else return POSITIVE_ZERO | (x ^ y) & 0x80000000000000000000000000000000;
} else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) {
if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
else return POSITIVE_INFINITY | (x ^ y) & 0x80000000000000000000000000000000;
} else {
uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (yExponent == 0) yExponent = 1;
else ySignifier |= 0x10000000000000000000000000000;
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) {
if (xSignifier != 0) {
uint shift = 226 - msb (xSignifier);
xSignifier <<= shift;
xExponent = 1;
yExponent += shift - 114;
}
}
else {
xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114;
}
xSignifier = xSignifier / ySignifier;
if (xSignifier == 0)
return (x ^ y) & 0x80000000000000000000000000000000 > 0 ?
NEGATIVE_ZERO : POSITIVE_ZERO;
assert (xSignifier >= 0x1000000000000000000000000000);
uint256 msb =
xSignifier >= 0x80000000000000000000000000000 ? msb (xSignifier) :
xSignifier >= 0x40000000000000000000000000000 ? 114 :
xSignifier >= 0x20000000000000000000000000000 ? 113 : 112;
if (xExponent + msb > yExponent + 16497) { // Overflow
xExponent = 0x7FFF;
xSignifier = 0;
} else if (xExponent + msb + 16380 < yExponent) { // Underflow
xExponent = 0;
xSignifier = 0;
} else if (xExponent + msb + 16268 < yExponent) { // Subnormal
if (xExponent + 16380 > yExponent)
xSignifier <<= xExponent + 16380 - yExponent;
else if (xExponent + 16380 < yExponent)
xSignifier >>= yExponent - xExponent - 16380;
xExponent = 0;
} else { // Normal
if (msb > 112)
xSignifier >>= msb - 112;
xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent = xExponent + msb + 16269 - yExponent;
}
return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) |
xExponent << 112 | xSignifier));
}
}
/**
* Get index of the most significant non-zero bit in binary representation of
* x. Reverts if x is zero.
*
* @return index of the most significant non-zero bit in binary representation
* of x
*/
function msb (uint256 x) private pure returns (uint256) {
require (x > 0);
uint256 result = 0;
if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; }
if (x >= 0x10000000000000000) { x >>= 64; result += 64; }
if (x >= 0x100000000) { x >>= 32; result += 32; }
if (x >= 0x10000) { x >>= 16; result += 16; }
if (x >= 0x100) { x >>= 8; result += 8; }
if (x >= 0x10) { x >>= 4; result += 4; }
if (x >= 0x4) { x >>= 2; result += 2; }
if (x >= 0x2) result += 1; // No need to shift x anymore
return result;
}
}
/*
USAGE NOTE: calculateUINT will return a uint value for lock time. However, due to ABDK conversion, the number might appear
arbitrary. You might need to multiply it by a constant, K, to get it to look right. Feed in values to get the minimum
and maximum lock times and then, if needs be, figure out K.
EG. You want minimum lock time to be 2000 and maximum to be 10000 (fictional numbers). Howver calculateUIN returns a range of 400 to 2000.
Then you know K must be 5.
*/
//P is from uniswap: price R3T price in terms of Eth
contract PermanentLockPercentage{
using ABDKMathQuad for bytes16;
using ABDKMathQuad for uint;
address public R3T;
UniswapV2Router02 uniswapRouter;
TokenPair tokenPair;
bool token0IsR3T;
//as per doc, alpha is set to 1 to save gas and get a good enough result
struct ParameterSet {
bytes16 d_max; //maximum lock percentage
bytes16 P0; //normal price
bytes16 d0; //normal permanent lock percentage
bytes16 beta; //Calibration coefficient
}
ParameterSet calibration;
//add an onlyOwner modifier
function calibrate(uint d_max,uint P0,uint d0,uint beta) public {
calibration.d_max = d_max.fromUInt();
calibration.P0 = P0.fromUInt();
calibration.d0 = d0.fromUInt();
calibration.beta = beta.fromUInt();
}
constructor(address _R3T, address _router, address _tokenPair) {
R3T = _R3T;
uniswapRouter = UniswapV2Router02(_router);
tokenPair = TokenPair(_tokenPair);
(address token0, ) = R3T < uniswapRouter.WETH()
? (R3T, uniswapRouter.WETH())
: ( uniswapRouter.WETH(), R3T);
token0IsR3T = token0==R3T;
}
function R3TEthPrice(uint amount) internal view returns (uint) {
(uint256 reserve1, uint256 reserve2, ) = tokenPair.getReserves();
if(token0IsR3T){
return uniswapRouter.quote(
amount,
reserve2,
reserve1
);
}else{
return uniswapRouter.quote(
amount,
reserve2,
reserve1
);
}
}
function calculateUINT(uint amount) public view returns (uint) {
return calculate(amount).toUInt();
}
//use ABDK to perform necessary conversion
function calculate(uint amount) public view returns (bytes16) {
//d = d_max*(1/(b.p+1));
bytes16 ONE = uint(1).fromUInt();
bytes16 price = R3TEthPrice(amount).fromUInt();
bytes16 denominator = calibration.beta.mul(price).add(ONE);
bytes16 factor = ONE.div(denominator);
return calibration.d_max.mul(factor);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment