Open EGreg opened 2 years ago
Note: we may have a feature to reduce the sales price over time, if no one is buying at the all-time-high price. (This could happen because Intercoin is trading on exchanges somewhere else. But it also means that ITR holders are missing out on dividends they could get because the smart contract is not competing with the tighter spreads on those other exchanges.)
Most of the above stuff, including the currentIncrease
calculation would remain the same, but replace allTimeHigh
everywhere with currentPrice
.
Please read this article on bonding curves completely before beginning work.
string name, string ticker, uint256 initialIncrease, uint256 fractionToReserve, uint256 fractionToLiquidity, array disbursementList,
with defaults baked into the contract:"Intercoin", "INTER", 0.8, 0.05, 0.00000001, [[dividendsGroup, 100%]]
(converted to fixed-point math)initialIncrease
per INTER sold. Or they can send to the smart contract its own tokens and receive back ETH/BNB, with the price going down linearly as described in the section #5.fractionToReserve
is stored on reserve in ETH whilefractionToLiquidity
will be added to the ETH-INTER pairs on UniSwap or PancakeSwap (the most-used exchanges, respectively). These pairs can be calculated in advance, if we know what the contract's address will be (using vanity.eth) so we don't even need the owner to set them and then renounceOwnership. We will just put them into initparameters when deploying on the blockchain.disbursementList
, and then you are supposed to calldisburse()
on each contract in that list. Make asetDividendsList(dividendsList) onlyOwner
method, so owner can change list until they renounce ownership, and it will check whether the keccak ofdisburse()
is callable on each contract in the list.Reasoning
Explanation #1: Why do we use ETH/BNB? Because the assumption is that if the blockchain is operational, then the most decentralized asset on it is its own coin (instead of USDT, or USDC, which relies on off-chain guarantees by centralized entities that may not be true in 20-30 years). If you have questions about the math, contact me.
Explanation #2: Since
fractionToReserves
is kept on reserve for buybacks, you can imagine a trapezoid which starts at 0 and increases bycurrentIncrease * fractionToReserves
for every 1 INTER sold. If everyone wanted to sell back to the contract at the same price, the price would then have to be:(allTimeHigh / 2) * fractionToReserves
. So to give a real example, that could be~ (allTimeHigh / 2 * 80%) = allTimeHigh * 40%
. Thus everyone would get 40% of their money back. But we don't want to give everyone the same amount. Rather, we want to start giving 80% of the allTimeHigh and move down to 0% for the very last INTER bought back ( 40 is in the middle between 80 and 0 ). Thus the actual buyback price would be a line with a midpoint at atallTimeHigh / 2
and negative slope. Note that even though the smart contract reduces the buyback price as its reserves reduce, it doesn't reduce the sell price! New Intercoins can only be bought at the all-time high. If people think that price is too high, they will start to buy from other people. The smart contract only dispenses new Intercoins when the market demands them (i.e. more communities, and larger local economies) and is willing to pay above the all-time-high price. Until then, the Intercoins can list in secondary markets and have wide availability trading on many exchanges against many currencies (see https://intercoin.org/tokenomics)Explanation #3: How do we calculate the price curve and let the buybacks be sustainable?
First of all let's look at redeeming tokens, when the contract has a certain reserve fund build up. If all the tokens were to be redeemed at the all-time-high price, the contract would need to have
totalRefund = totalSupplyOfTokens * allTimeHighPrice
coins, and its reserves are actually a lot lower. Over time, the area under a diagonal line (triangle) approaches 50% of the area under the rectangle (even if the initial price wouldn't have been zero, it becomes insignificant). So the smart contract has about half of the 80% it put on reserve, in other words around 40%. It could give out coins at a constant price of 40% of ATH, but we want the earliest people to get it at a better price, and latest people get it at a lower price near zero, so we tilt the horizontal line. In our example, start at 80% of all-time-high price for the first tokens, and end with 10% of all-time-high price for the last tokens (40 is in the midpoint between 70 and 10).However, the reserve ratio would fall after every buyback. The smart contract has to use its reserves to buy back tokens whenever someone wants to redeem them. But since the contract doesn't reduce its sales price, the very next person who comes to buy would be buying at the all-time-high price, causing the reserve ratio to fall even lower (relative to having to buy back ALL tokens at the all-time-high price). To mitigate this, we must make the
increasePrice
speed slow down proportionally to the decline in the reserve ratio. So the initial reserve ratio starts out at 40%= initialReserveRatio = fractionToReserve / 2
. But at every moment when we buy, just calculatecurrentReserveRatio = currentReserve / totalRefund
and just set:Thus, the rate at which the price grows would slow down every time the smart contract buys back some tokens. It might eventually get so slow as to become almost a stablecoin, until the reserves build back up as people buy more coins, and then the growth picks up again.
The Mathematics
We are inspired by Bancor's Reserve Ratio with 50% kept on reserve, but rescaled by
fractionToReserve
(i.e. 80% of 50%). There, we use thecalculatePurchaseReturn
andcalculateSaleReturn
from that article, but here we will modify the logic, so let's reason through it together!For buying back tokens it's easy, because the horizontal axis is in "tokens being redeemed", and users are redeeming tokens with smart contract. So to know the number of coins to give out, first consider if all the coins were given at a constant price of
remainingBalanceOfCoins / totalSupplyOfTokens
(40% in the example above where everyone only bought, and then everyone only sold). But we want the earliest people to get it at a better price, and latest people get it at a lower price near zero (in our example, start at 80% of all-time-high price for the first tokens, and end with 0% of all-time-high price for the last tokens). We can just "tilt the line" around the midpoint, and take the integral under the line, which is simply calculated asa * t + b * t^2/2
. To keep things simple, let's make the first tokens sell for twice the reserve ratio (80% of All Time High price) and the last tokens sell for 0. This can always be possible regardless of the current reserve ratio.For selling tokens, it's more complex. because the horizontal axis is in "tokens being bought", but users are sending coins, so we must do some algebra to solve for the number of tokens to return, using the number of coins (like ETH or BNB) the user is sending to the contract. So we do the integral math and find the indefinite integral of the function to be
Integral(price)(t) = currentPrice * t + currentIncrease * t^2 / 2
. Basically, we're talking about getting the area of the rectangle on the bottom, plus a triangle sitting on top of it:Thus, given the current price of
allTimeHigh
, and currenttotalSupply
asT
(a known constant during the transaction) we want to solve for and solve fort = tokensToSend
in the following formula:a quadratic expression where
A = currentIncrease / 2
andB = allTimeHigh
solving with quadratic formula gives:
Just try "-B +" or "-B -" and maybe flip the sign, to send tokens. Test and you know how many tokens to send. This formula would be the same all the time once you get it, you only have to experiment with flipping signs in math, not in the code.
So that is how you calculate how many tokens to send to the user.