This repository has been archived on 2023-03-01. You can view files and clone it, but cannot push or open issues or pull requests.
Go to file
Mohamed Sohail 99a9915d11 Merge branch 'dev-0.2.0' into 'master'
Runaway redistribution

See merge request cicnet/erc20-demurrage-token!10
2022-05-30 07:53:22 +00:00
python Runaway redistribution 2022-05-30 07:53:22 +00:00
solidity Runaway redistribution 2022-05-30 07:53:22 +00:00
.gitignore ci: add basic ci 2022-03-02 08:54:20 +00:00
.gitlab-ci.yml ci: add basic ci 2022-03-02 08:54:20 +00:00 Cleanup, docs, benchmarks 2021-03-01 09:53:39 +00:00


Use Case

  • Network / Basic Income Token
    • 100 Sarafu is distributed to anyone in Kenya after user validation by the owner of a faucet which mints new Sarafu.
      • Validated users are those that validate their phone number in Kenya.
    • A Sarafu holding tax aka (demurrage) of 0.000050105908373373% is charged from users per minute - such that over 1 month to total tax would be 2%.
    • After 1 week the total amount tax is distributed evenly out to active users.
      • any single transaction by a user within that week is considered active (heartbeat)
    • This is meant to result in a disincentivization to hold (hodl) the Sarafu token and increase its usage as a medium of exchange rather than a store of value.
    • This token can be added to liquidity pools with other ERC20 tokens and or Community Inclusion Currencies (CICs) - and thereby act as a central network token and connect various tokens and CICs together.
    • Example
      • With a demurrage of 2% (net per month) and a reward period of 1 month - If there are 10 users all with balances of 1000 Sarafu and only 2 of them trade that month (assume they trade back and forth with no net balance change).
      • Then the resulting balances after one tax period of those two trading would be 1080 Sarafu while the remaining non-active users would be 980 Sarafu. If this behaviour continued in the next tax period, with the same two users only trading (with no net balance changes), they would have 1158.39999968 Sarafu and those users that are not trading would have their balances further reduced to 960.40 Sarafu. If this continued on ~forever those two active trading users would have the entire token supply and the non-trading users would eventually reach a zero balance.
      • this example calculation for 3 tax periods can be found here:


  • Demurrage aka Decay amount: A percentage of token supply that will be charged once per minute and evenly redistributed to active users every Demurrage Period (minutes)
  • Base balance: The inflated balance of each user is stored for bookkeeping.
  • Sink Token Address: Rounding errors and if no one trades the tax goes to this address
  • Demurrage Period (minutes)- aka period: The number of minutes over which a user must be active to receive tax-redistibution.


  • Contract creator is owner
  • Ownership can be transferred


  • Owner can add minters and remove
    • A faucet contract would be a minter and choose the amount of tokens to mint and distribute to new validated users.
    • The interface says the amount and is at the caller's discretion per contract call. validation is outside of this contract.
  • A minter can remove itself
  • Minters can mint any amount


  • Holding Tax (demurrage) is applied when a mint or transfer; (it can also be triggered explicitly)
    • Note that the token supply stays the same but a virtual balance output is created.
    • Updates demurrageModifier which represents the accumulated tax value and is an exponential decay step (of size demurrage) for each minute that has passed.
      • demurrageModifier = (1-demurrage)^(minute_passed)
        • e.g. a demurrage of 2% after the 1st minute would be give a demurrageModifier = (1-0.02)^1 = 0.98.
        • e.g. a demurrage after the 2nd minute would be give a demurrageModifier = (1-0.02)^2 = 0.9604.
  • All client-facing values (balance output , transfer inputs) are adjusted with demurrageModifier.
    • e.g. _balance output_ = user_balance - user_balance * demurrageModifier


  • One redistribution entry is added to storage for each period;
    • When mint is triggered, the new totalsupply is stored to the entry
    • When transfer is triggered, and the account did not yet participate in the period, the entry's participant count is incremented.
  • Account must have "participated" in a period to be redistribution beneficiary.
  • Redistribution is applied when an account triggers a transfer for the first time in a new period;
    • Check if user has participated in period. (active user heartbeat)
    • Each active user balance in the period is increased by (total supply at end of period * demurrageModifier ) / number_of_active_participants via minting
    • Participation field is zeroed out for that user.
  • Fractions must be rounded down
    • Remainder is "dust" and should be sent to a dedicated Sink Token Address.
    • If no one is active all taxes go to the Sink Token Address.

Data structures

  • One word per account:
    • bits 000-071: value
    • bits 072-103: period
    • bits 104-255: (Unused)
  • One word per redistributions period:
    • bits 000-031: period
    • bits 032-103: supply
    • bits 104-139: participant count
    • bits 140-159: demurrage modifier
    • bits 160-254: (Unused)
    • bits 255: Set if individual redistribution amounts are fractions


Accumulated demurrage modifier in demurrageModifier is 128 bit, but will be truncated do 20 bits in redistributions. The 128 bit resolution is to used to reduce the impact of fractional drift of the long-term accumulation of the demurrage modifier. However, the demurrage snapshot values used in redistributions are parts-per-million and can be fully contained within a 20-bit value.


  • Basic python tests in place
  • How to determine and generate sufficient test vectors, and how to adapt them to scripts.
  • Audit sources?

Known issues

  • A transferFrom following an approve call, when called across period thresholds, may fail if margin to demurraged amount is insufficient.