BancorFormula
Author: Bancor
This contract provides functions for calculating the purchase and sale return values on an exponential curve using a reserve ratio. The formula converts a given reserve token amount into a token return and the sale of a token amount into a reserve token return.
This is an updated version of the BancorFormula contract from the Bancor Protocol. Editted to be compatible with Solidity 0.8.28. See README.md for detailed changes.
State Variables
MIN_PRECISION
Minimum precision index in the maxExpArray
uint8 private constant MIN_PRECISION = 32;
MAX_PRECISION
Maximum precision index in the maxExpArray
uint8 private constant MAX_PRECISION = 127;
MAX_RATIO
Max reserve ratio in parts per million
uint32 private constant MAX_RATIO = 1000000;
ONE
Constant variable for 1
uint256 private constant ONE = 1;
FIXED_1
Represents 2 to the power of 127 or 1.7014e38
uint256 private constant FIXED_1 = 0x080000000000000000000000000000000;
FIXED_2
Represents 2 to the power of 128 or 3.4028e38
uint256 private constant FIXED_2 = 0x100000000000000000000000000000000;
MAX_NUM
Represents 2 to the power of 129 or 6.8056e38
uint256 private constant MAX_NUM = 0x200000000000000000000000000000000;
LN2_NUMERATOR
Numerator used to convert from base 2 to natural logarithm
uint256 private constant LN2_NUMERATOR = 0x3f80fe03f80fe03f80fe03f80fe03f8;
LN2_DENOMINATOR
Denominator used to convert from base 2 to natural logarithm
uint256 private constant LN2_DENOMINATOR = 0x5b9de1d10bf4103d647b0955897ba80;
OPT_LOG_MAX_VAL
Max value at which the _optimalLog function approximations are still effective
uint256 private constant OPT_LOG_MAX_VAL = 0x15bf0a8b1457695355fb8ac404e7a79e3;
OPT_EXP_MAX_VAL
Max value at which the _optimalExp function approximations are still effective
uint256 private constant OPT_EXP_MAX_VAL = 0x800000000000000000000000000000000;
maxExpArray
The array of values used to find the precision needed for the given input
uint256[128] private maxExpArray;
Functions
constructor
Since maxExpArray is a fixed-size array, we need to initialize it in the constructor. To expand the array at the cost of higher gas fees, uncomment the following lines.
constructor();
_calculateBancorFormulaPurchaseReturn
Returns the purchase value for a given amount (in the reserve token) as a conversion into the main token.
Formula: Return = supply * ((1 + depositAmount / reserveBalance) ^ (reserveRatio / 1000000) - 1)
function _calculateBancorFormulaPurchaseReturn(
uint256 supply,
uint256 reserveBalance,
uint32 reserveRatio,
uint256 depositAmount
) internal view returns (uint256 purchaseReturn);
Parameters
supply
uint256
token total supply
reserveBalance
uint256
balance of reserve token
reserveRatio
uint32
reserve ratio, represented in ppm, 1-1000000
depositAmount
uint256
deposit amount, in reserve token
Returns
purchaseReturn
uint256
return of the conversion
_calculateBancorFormulaSaleReturn
Returns the sale value for a given amount (in the main token) as a conversion into the reserve token.
Formula: Return = reserveBalance * (1 - (1 - sellAmount / supply) ^ (1 / (reserveRatio / 1000000)))
function _calculateBancorFormulaSaleReturn(
uint256 supply,
uint256 reserveBalance,
uint32 reserveRatio,
uint256 sellAmount
) internal view returns (uint256 saleReturn);
Parameters
supply
uint256
token total supply
reserveBalance
uint256
total reserve
reserveRatio
uint32
reserve ratio, represented in ppm, 1-1000000
sellAmount
uint256
amount of tokens to sell
Returns
saleReturn
uint256
return of the conversion
_power
Returns the exponentiation result along with the precision used.
Detailed Description:
Instead of calculating "base ^ exp", we calculate "e ^ (log(base) * exp)".
The value of "log(base)" is represented with an integer slightly smaller than "log(base) * 2 ^ precision".
The larger "precision" is, the more accurately this value represents the real value.
However, the larger "precision" is, the more bits are required in order to store this value.
And the exponentiation function, which takes "x" and calculates "e ^ x", is limited to a maximum exponent (maximum value of "x").
This maximum exponent depends on the "precision" used, and it is given by "maxExpArray[precision] >> (MAX_PRECISION - precision)".
Hence we need to determine the highest precision which can be used for the given input, before calling the exponentiation function.
This allows us to compute "base ^ exp" with maximum accuracy and without exceeding 256 bits in any of the intermediate computations.
This functions assumes that "expN < 2 ^ 256 / log(MAX_NUM - 1)"
function _power(uint256 baseN, uint256 baseD, uint32 expN, uint32 expD)
internal
view
returns (uint256 result, uint8 precision);
Parameters
baseN
uint256
base numerator
baseD
uint256
base denominator
expN
uint32
exponent numerator
expD
uint32
exponent denominator
Returns
result
uint256
exponentiation result
precision
uint8
precision used
_findPositionInMaxExpArray
The global "maxExpArray" is sorted in descending order, and therefore the following statements are equivalent:
Returns the position of [the smallest value in "maxExpArray" larger than or equal to "x"].
Returns the highest position of [a value in "maxExpArray" larger than or equal to "x"].
function _findPositionInMaxExpArray(uint256 x) internal view returns (uint8 position);
Parameters
x
uint256
input
Returns
position
uint8
position of the value in the array
_generalLog
Returns the logarithm of a given input.
This functions assumes that "x >= FIXED_1", because the output would be negative otherwise.
function _generalLog(uint256 x) internal pure returns (uint256 result);
Parameters
x
uint256
input
Returns
result
uint256
logarithm of x
_floorLog2
Returns the largest integer smaller than or equal to the binary logarithm of the input.
function _floorLog2(uint256 x) internal pure returns (uint8 result);
Parameters
x
uint256
input
Returns
result
uint8
result
_generalExp
Returns the exponentiation of a given input.
It approximates "e ^ x" via maclaurin summation: "(x^0)/0! + (x^1)/1! + ... + (x^n)/n!".
It returns "e ^ (x / 2 ^ precision) * 2 ^ precision", that is, the result is upshifted for accuracy.
The global "maxExpArray" maps each "precision" to "((maximumExponent + 1) << (MAX_PRECISION - precision)) - 1".
The maximum permitted value for "x" is therefore given by "maxExpArray[precision] >> (MAX_PRECISION - precision)".
function _generalExp(uint256 x, uint8 precision) internal pure returns (uint256 result);
Parameters
x
uint256
input
precision
uint8
precision
Returns
result
uint256
result
_optimalLog
Returns the logarithm of a given input.
Returns log(x / FIXED_1) * FIXED_1. Input range: FIXED_1 <= x <= OPT_LOG_MAX_VAL - 1.
*Detailed description:
Rewrite the input as a product of natural exponents and a single residual r, such that 1 < r < 2.
The natural logarithm of each (pre-calculated) exponent is the degree of the exponent.
The natural logarithm of r is calculated via Taylor series for log(1 + x), where x = r - 1.
The natural logarithm of the input is calculated by summing up the intermediate results above.
For example: log(250) = log(e^4 * e^1 * e^0.5 * 1.021692859) = 4 + 1 + 0.5 + log(1 + 0.021692859).*
function _optimalLog(uint256 x) internal pure returns (uint256 result);
Parameters
x
uint256
input
Returns
result
uint256
result
_optimalExp
Returns the exponentiation of a given input.
Return e ^ (x / FIXED_1) * FIXED_1. Input range: 0 <= x <= OPT_EXP_MAX_VAL - 1.
*Detailed description:
Rewrite the input as a sum of binary exponents and a single residual r, as small as possible.
The exponentiation of each binary exponent is given (pre-calculated).
The exponentiation of r is calculated via Taylor series for e^x, where x = r.
The exponentiation of the input is calculated by multiplying the intermediate results above.
For example: e^5.021692859 = e^(4 + 1 + 0.5 + 0.021692859) = e^4 * e^1 * e^0.5 * e^0.021692859.*
function _optimalExp(uint256 x) internal pure returns (uint256 result);
Parameters
x
uint256
input
Returns
result
uint256
result
Errors
BancorFormula__InvalidInput
error BancorFormula__InvalidInput();
Last updated