Skip to content

Instantly share code, notes, and snippets.

@zsfelfoldi
Last active February 18, 2020 14:45
Show Gist options
  • Save zsfelfoldi/ac823b7d3b7b4b3471474270cce8cc8f to your computer and use it in GitHub Desktop.
Save zsfelfoldi/ac823b7d3b7b4b3471474270cce8cc8f to your computer and use it in GitHub Desktop.

A quick explanation of the expiredValue structure

Goal

The lesPay token sale model uses service tokens that continuously "expire" under certain conditions, meaning their value is reduced exponentially over time. Expiration happens when some amount of free connection is possible and therefore all existing tokens are spendable. Expiration can be interpreted as a kind of "spendability" fee that incentivizes clients to indeed spend their tokens in a limited time frame. This can be realized in two ways:

  • with "inflationary" units; if all prices rise exponentially then value of existing tokens is reduced inversely
  • with "stable tokens"; if the nominal value of each token is stable then the token balances should be reduced continuously

The second interpretation fits with the model better because service tokens (which are basically a promise from the server) are meant to have a more or less predictable purchasing power. With stable token nominations the client can expect the prices to not change quickly which is a reasonable expectation after buying service tokens.

On the other hand, the inflationary model is easier to handle technically because it does not require regularly updating all balance amounts (both in memory and database) throughout the system. This is what expiredValue implements; it stores values internally in an inflationary format but allows adding and retrieving values in stable format. It assumes a global logOffset value that accumulates token expiration and is basically the logarithm of the exchange rate between "stable" and "inflationary" units.

Realization

Ideally, the conversion would be very simple:

expiredValue = tokenAmount*e^logOffset
tokenAmount = expiredValue*e^(-logOffset)

A little trick is required though in order to avoid numerical problems. Since logOffset grows monotonically throughout the lifetime of the system, the exchange rate can grow very big. This could be an ideal use case for floating point arithmetics but unfortunately even float64 could overflow eventually. This is why expiredValue is made of a 64 bit base value and a 64 bit exponent. The "inflationary" amount can be calculated as base * 2^exp. Negative numbers and fractional parts are not needed here so both are non-negative. logOffset is a fixed-point value which can be interpreted either as a 2-base or a natural logarithm by using different multiplier constants (either logMultiplier or log2Multiplier). The conversion rate from stable to inflationary is therefore e^(logOffset/logMultiplier). Calculating this value directly as a float64 would still not avoid overflow though, so we calculate the base and exponent separately by splitting logOffset to integer and fractional parts (interpreted as base 2 this time):

logint = uint64(logOffset / log2Multiplier)		// since log2Multiplier = 2^24, this is the higher 40 bits of logOffset
logfrac = logOffset % log2Multiplier			// this is the lower 24 bits of logOffset

Then we can use logint directly as the exponent for expiredValue while the exponential of logfrac can be calculated as floating point (this time interpreted as a natural logarithm in order to be able to use floating point exponential function):

expiredValue.base = uint64(tokenAmount*math.Exp(float64(logfrac)/logMultiplier))
expiredValue.exp = logint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment