This builds on the Basic CW20 interface
as implemented in cw20-base
.
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)
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
Note: the first version only accepts native tokens as the
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. There is also a crate to provide nth-root of for all integers. With these two, we can handle most math except for logs/exponents.
Compare this to writing it all in solidity
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.