103 lines
3.2 KiB
Solidity
103 lines
3.2 KiB
Solidity
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
pragma solidity ^0.8.15;
|
|
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
|
|
|
|
/**
|
|
* @title SafeMathInt
|
|
* @dev Math operations for int256 with overflow safety checks.
|
|
*/
|
|
library SafeMathInt {
|
|
int256 private constant MIN_INT256 = int256(1) << 255;
|
|
int256 private constant MAX_INT256 = ~(int256(1) << 255);
|
|
|
|
/**
|
|
* @dev Multiplies two int256 variables and fails on overflow.
|
|
*/
|
|
function mul(int256 a, int256 b) internal pure returns (int256) {
|
|
int256 c = a * b;
|
|
|
|
// Detect overflow when multiplying MIN_INT256 with -1
|
|
require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));
|
|
require((b == 0) || (c / b == a));
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* @dev Division of two int256 variables and fails on overflow.
|
|
*/
|
|
function div(int256 a, int256 b) internal pure returns (int256) {
|
|
// Prevent overflow when dividing MIN_INT256 by -1
|
|
require(b != -1 || a != MIN_INT256);
|
|
|
|
// Solidity already throws when dividing by 0.
|
|
return a / b;
|
|
}
|
|
|
|
/**
|
|
* @dev Subtracts two int256 variables and fails on overflow.
|
|
*/
|
|
function sub(int256 a, int256 b) internal pure returns (int256) {
|
|
int256 c = a - b;
|
|
require((b >= 0 && c <= a) || (b < 0 && c > a));
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* @dev Adds two int256 variables and fails on overflow.
|
|
*/
|
|
function add(int256 a, int256 b) internal pure returns (int256) {
|
|
int256 c = a + b;
|
|
require((b >= 0 && c >= a) || (b < 0 && c < a));
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* @dev Converts to absolute value, and fails on overflow.
|
|
*/
|
|
function abs(int256 a) internal pure returns (int256) {
|
|
require(a != MIN_INT256);
|
|
return a < 0 ? -a : a;
|
|
}
|
|
|
|
/**
|
|
* @dev Computes 2^exp with limited precision where -100 <= exp <= 100 * one
|
|
* @param one 1.0 represented in the same fixed point number format as exp
|
|
* @param exp The power to raise 2 to -100 <= exp <= 100 * one
|
|
* @return 2^exp represented with same number of decimals after the point as one
|
|
*/
|
|
function twoPower(int256 exp, int256 one) internal pure returns (int256) {
|
|
bool reciprocal = false;
|
|
if (exp < 0) {
|
|
reciprocal = true;
|
|
exp = abs(exp);
|
|
}
|
|
|
|
// Precomputed values for 2^(1/2^i) in 18 decimals fixed point numbers
|
|
int256[5] memory ks = [
|
|
int256(1414213562373095049),
|
|
1189207115002721067,
|
|
1090507732665257659,
|
|
1044273782427413840,
|
|
1021897148654116678
|
|
];
|
|
int256 whole = div(exp, one);
|
|
require(whole <= 100);
|
|
int256 result = mul(int256(uint256(1) << uint256(whole)), one);
|
|
int256 remaining = sub(exp, mul(whole, one));
|
|
|
|
int256 current = div(one, 2);
|
|
for (uint256 i = 0; i < 5; i++) {
|
|
if (remaining >= current) {
|
|
remaining = sub(remaining, current);
|
|
result = div(mul(result, ks[i]), 10**18); // 10**18 to match hardcoded ks values
|
|
}
|
|
current = div(current, 2);
|
|
}
|
|
if (reciprocal) {
|
|
result = div(mul(one, one), result);
|
|
}
|
|
return result;
|
|
}
|
|
}
|