# CW20 Bonding curve
This builds on the [Basic CW20 interface](../../packages/cw20/README.md)
as implemented in [`cw20-base`](../cw20-base/README.md).
This serves three purposes:
* A usable and extensible contract for arbitrary bonding curves
* A demonstration of how to extend `cw20-base` to add extra functionality
* A demonstration of the [Receiver interface]([Basic CW20 interface](../../packages/cw20/README.md#receiver))
## Design
There are two variants - accepting native tokens and accepting cw20 tokens
as the *reserve* token (this is the token that is input to the bonding curve).
Minting: When the input is sent to the contract (either via `ExecuteMsg::Buy{}`
with native tokens, or via `ExecuteMsg::Receive{}` with cw20 tokens),
those tokens remain on the contract and it issues it's own token to the
sender's account (known as *supply* token).
Burning: We override the burn function to not only burn the requested tokens,
but also release a proper number of the input tokens to the account that burnt
the custom token
Curves: `handle` specifies a bonding function, which is sent to parameterize
`handle_fn` (which does all the work). The curve is set when compiling
the contract. In fact many contracts can just wrap `cw20-bonding` and
specify the custom curve parameter.
Read more about [bonding curve math here](https://yos.io/2018/11/10/bonding-curves/)
Note: the first version only accepts native tokens as the
### Math
Given a price curve `f(x)` = price of the `x`th token, we want to figure out
how to buy into and sell from the bonding curve. In fact we can look at
the total supply issued. let `F(x)` be the integral of `f(x)`. We have issued
`x` tokens for `F(x)` sent to the contract. Or, in reverse, if we send
`x` tokens to the contract, it will mint `F^-1(x)` tokens.
From this we can create some formulas. Assume we currently have issued `S`
tokens in exchange for `N = F(S)` input tokens. If someone sends us `x` tokens,
how much will we issue?
`F^-1(N+x) - F^-1(N)` = `F^-1(N+x) - S`
And if we sell `x` tokens, how much we will get out:
`F(S) - F(S-x)` = `N - F(S-x)`
Just one calculation each side. To be safe, make sure to round down and
always check against `F(S)` when using `F^-1(S)` to estimate how much
should be issued. This will also safely give us how many tokens to return.
There is built in support for safely [raising i128 to an integer power](https://doc.rust-lang.org/std/primitive.i128.html#method.checked_pow).
There is also a crate to [provide nth-root of for all integers](https://docs.rs/num-integer/0.1.43/num_integer/trait.Roots.html).
With these two, we can handle most math except for logs/exponents.
Compare this to [writing it all in solidity](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7b7ff729b82ea73ea168e495d9c94cb901ae95ce/contracts/math/Power.sol)
Examples:
Price Constant: `f(x) = k` and `F(x) = kx` and `F^-1(x) = x/k`
Price Linear: `f(x) = kx` and `F(x) = kx^2/2` and `F^-1(x) = (2x/k)^(0.5)`
Price Square Root: `f(x) = x^0.5` and `F(x) = x^1.5/1.5` and `F^-1(x) = (1.5*x)^(2/3)`
We will only implement these curves to start with, and leave it to others to import this with more complex curves,
such as logarithms.