# Price The price definition used throughout the codebase is not very intuitive. It was derived from the necessity to achieve sufficient precision using integer math. Therefore, it is explained here for reference whenever needed. ## Terms used ### bit A bit is the smallest subunit of a token, in accordance with [OpenZeppelin's original definition](https://web.archive.org/web/20191212000648/docs.openzeppelin.com/contracts/2.x/crowdsales): > In Ether, the smallest unit of the currency is wei, and 1 ETH === 10^18 wei. In tokens, the process is very similar: 1 TKN === 10^(decimals) TKNbits. > > - The smallest unit of a token is "bits" or TKNbits. > - The display value of a token is TKN, which is TKNbits \* 10^(decimals) > > What people usually call "one token" is actually a bunch of TKNbits, displayed to look like 1 TKN. This is the same relationship that Ether and wei have. And what you're always doing calculations in is TKNbits and wei. ### tokenPrice The tokenPrice is the "amount of subunits of currency per main unit token (e.g.: 2 USDC (6 decimals) per TOK (18 decimals) => price = 2\*10^6 )" ### token Token will be abbreviated: - T for full tokens (as in `10^decimals` bits) - Tbit for bits of the token ## Definition In order to make sure price can be expressed exactly with integers, the definition was chosen as: ```solidity price = PaymentTokenBits/Token = PaymentTokenBits/TokenBits * 10**Token.decimals() ``` With this, the payment amount could be calculated from the token amount as: ```solidity paymentAmount = (_tokenAmount * tokenPrice) / (10**token.decimals()) ``` Since this is done using integer math, it rounds down by default. For example: - T has 18 decimals, so one bit - USDC has 6 decimals So if price was defined as 1 USDC/T and the investor wanted to buy 1Tbit, they would have to pay 10^-18 USDC, which would be rounded to 0 USDC because 1 USDCbit = 10^-6 USDC. They would get a fraction of a token for free. Giving away equity without payment is not acceptable. Therefore, the calculation is done rounding up to the next integer, using openzeppelin's ceilDiv function: ```solidity paymentAmount = Math.ceilDiv(_tokenAmount * tokenPrice, 10**token.decimals()) ``` The error introduced by rounding is less than or equal to one currency bit. For USDT, this would result in a maximum error of 0.000001 USD. They are negligible for all practical purposes. ## Example (with rounding error=0) - [currency] = USDC - USDC has 6 decimals (https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) - so 2.7 USDC = 2.7 \* 10\*\*6 USDCbit = 2700000 USDCbit - assume 3 token (which is 3 \* 10\*\*18 token bits) should be sold for 600 USDC - so 1 token costs 200 USDC - then tokenPrice is: ```solidity 600 USDC / 3 T = 600 * 10**6 USDCbit / 3 T = 200 * 10**6 USDCbit/T = 2 * 10**8 USDCbit/T ``` The unit is omitted, so the price will be 2\*10^8 - investor wants to buy 150 tokens - they call Crowdinvesting.buy(150 \* 10\*\*18, 150 \* 200 \* 10\*\*6, tokenReceiver) - so \_tokenAmount is 150 \* 10\*\*18 - 150 \* 10^18 \* 2 \* 10^8 = 300 \* 10^26 = 3 \* 10^28 - calculate amount due in USDC bits: 3 \* 10^28/10^18 = 3 \* 10^10 - amount due in USDC: 3 \* 10^10 / 10^6 = 3 \* 10^4 = 30000 USDC - 30000 USDC / (200 USDC/T) = 150T -> this worked well ## Exchange rates The same formula is used in [Exit.sol](../contracts/Exit.sol) to express the exchange rate between two currencies (`referenceToExitRate`). The meaning is slightly different — it converts a currency amount rather than a token amount into another currency — but the math is identical: ``` exitCurrencyBits = referenceCurrencyBits * rate / 10**referenceCurrency.decimals() ``` Because both `tokenPrice` and `referenceToExitRate` follow the same convention, they compose directly. Given a token price in currency B and a rate from currency B to currency C, the equivalent token price in currency C is: ``` price_tokenInCurrencyC = price_tokenInCurrencyB * rate_CurrencyBinCurrencyC / 10**decimalsB ``` The denominator is always the decimals of the **source** (intermediate) currency B, because the rate is defined as "currency C bits per 10^decimalsB currency B bits". Example: token price is 10 EURe/token (`price = 10e18`, EURe has 18 decimals), rate is 5 USDC/EURe (`rate = 5e6`, USDC has 6 decimals): ``` price_tokenInUSDC = 10e18 * 5e6 / 10**18 = 50e6 → 50 USDC/token ✓ ``` This composition is what `CoinvestedPosition.claimExit()` performs to determine the `effectiveBasePrice` in `exitCurrency` when the exit currency differs from the stored base currency and `referenceToExitRate` is set on the Exit contract. ## Comparing prices While the rounding error introduced in the paymentAmount is negligible, edge cases can result in seemingly large deviations in the actual price paid per token. Take the following example: - priceNominal = 1 currencyBits/token - tokenAmount = 1 tokenBit - this results in paymentAmount = 1 currencyBit - so the pricePaid is 1 currencyBit/tokenBit - with token.decimals() = 18, this results in: **pricePaid = priceNominal \* 10\*\*18** Keep in mind that this seemingly HUGE difference in price still results in a paymentAmount difference of only 1 currencyBit. Or, as was just explained, is the result thereof. The buyer can do all of these calculations beforehand, and just decide to buy the maximum amount of tokens possible for the currency they have to spend anyway. This is not enforced by the smart contracts though. It can be implemented in a frontend.