# Help fixed point math to initialize a bonding curve

I'm having difficulty computing an initial tokenSupply parameter in Solidity, one of two required parameters to initialize a Bancor-style bonding curve contract.

Formula:

P = sent Ether in Wei

R = reserve ratio

M = Slope

tokenSupply = (P/(R*M))^R

Suppose:

P = 1 * 10^18

R = .333333

M = .0025

N = Scaling Factor =  1/1,000,000

This seems fine:

tokenSupply = 1*10^18 / ((N)333,333 * (N)2500) * N

Now:

tokenSupply = ( 1*10^18 / (N)833 )^R

But #1:

Can I divide the unscaled wei by the scaled product (N)833 and assume the quotient has the same scaling factor N?

.#2:

How on earth do I raise this quotient to R? (Assuming R's initial Scaling Factor, 333,333 is out of the question) And how do I know what the scaling factor would be of the result tokenSupply? (I don't know how to handle scaled exponents). Thanks

I am using SafeMath to handle overflows

Can I divide the unscaled wei by the scaled product (833) and assume the quotient is the same scaling factor of the scaled product?

The question is not very clear to me, but tokenSupply = 1*10^18 / ((N)333,333 * (N)2500) * N seems wrong, as you are scaling the denominator by N*N but multiplying the result only by N.

If you're doing it off-chain, then there's no need for a scaling-factor whatsoever, and you can simply calculate P/(R*M).

If you're doing it on-chain, then you should multiply the result by N*N instead of by N. Also, please note that you're much better off doing it before you divide and not after.

To summarize this, you should do: P*N*N/(R*N*M*N).

P.S.: In your numeric example, you can use a smaller value of N (100K instead of 1M).

How on earth do I raise this quotient to R?

The reserve-ratio must be a value between 0 and 1.

If you're doing it off-chain, then simply raise to the power of R.

If you're doing it on-chain, then you can use Bancor's power function, which takes the exponent as a tuple of numerator and denominator, and pass to it your R as [333333, 1000000].

UPDATE:

If you are doing everything on-chain, then I recommend that you use Bancor's power function "all the way through":

uint256 result;
uint8 precision;
uint256 baseN = P.mul(10000000000);
uint256 baseD = R*M scaled by 10000000000
uint256 expN = R scaled by 1000000
uint256 expD = 1000000
(result, precision) = power(baseN, baseD, expN, expD);

At this point, the integer value of supply can be calculated using result >> precision.

• "tokenSupply = 1*10^18 / ((N)333,333 * (N)2500) * N seems wrong, as you are scaling the denominator by N*N but multiplying the result only by N" Rationale(wiki source): "If the two operands belong to the same fixed-point type, and the result is also to be represented in that type, then the product of the two integers must be explicitly multiplied by the common scaling factor" This brings the product from the intermediate scaling factor back to the original, no? N = 1/1,000,000 (N)X * (N)Y = N^2(XY) so N^2(XY) * N = (N)XY – Zach_is_my_name Jan 27 at 19:25
• @Zach_is_my_name: As in your original question, I find your descrition very hard to understand. In short, since you use N twice in the denominator, you should use it twice in the numerator. However, I'm not sure how you have R and M represented to begin with. Obviously, they're not given to you as 0.333333 and 0.0025, but as a pair of numerators and a pair of denominators... Or perhaps as a pair of numerators and a single denominator used for both. If that is indeed the case, and that denominator is N, then just make sure to multiply P by N*N instead of just by N. – goodvibration Jan 27 at 19:28
• This is building a constructor feeding arguments to Bancor's original BancorFormula.sol which takes connectorWeight (R) as a fraction in ppm hence 333333. I've assigned Slope (M) the same scaling factor. I'll look at and compare the operations you're proposing to the one's I'm using (taken from the source I cited). But even more helpful perhaps something you alluded to, doing the tokenSupply calculation off chain and seeing if the curve behaves as expected. Again this is to solve the problem of bootstapping a bonding curve with initial poolBalance (msg.value) and tokenSupply (pre-calculated) – Zach_is_my_name Jan 27 at 19:52