bom-contracts/contracts/mixins/SafeMathInt.sol
2022-07-25 18:40:16 +03:00

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;
}
}