Smart Contracts
Demurrage Voucher

Redistributed Demurrage Voucher


Use case

A Redistributed Demurrage Voucher could have the following use-cases:

  • A Publisher may publish a RedistributedDemurrageToken (Voucher) representing a credit obligation of an Issuer or Association of Issuers that can be redeemed as payment for the products of the Issuer. The Issuer is the entity legally obligated to redeem the voucher as payment.
  • Decay: The Publisher can specify an decay rate such as 2% as well as a redistribution period. After the redistribution period such as a month. Assuming an account holder has not had any transfers they will have a new balance of their original balance*2%. Note that the numeric decay will happen continuously by the minute.
  • Redistribution: The missing (demurraged) balances will be added to the balance of the SINK address. So once a redistribution period (e.g. once a month) the total supply of all holders including the SINK will return to the minted supply.
  • This is meant to result as a disincentivization to hold (hodl) the Voucher without causing price inflation, as the total supply is stable.
  • Example
    • With a demurrage of 2% (and redistribution period of 1 month) - If there are 10 users all with balances of 100 Vouchers (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 redistribution period of ALL users (regardless of their trading) would be 98 Vouchers and 20 Voucher would be the balance of the SINK address. Assuming the SINK address is redistributed (as a Community Fund) back to users, it’s balance would again reach 20 the next redistribution period.
    • Note that after the redistribution the total of all balances will equal the total minted amount.
    • Note that all accounts holding such Vouchers are effected by demurrage.


  • Demurrage aka Decay amount: A percentage of token supply that will gradually be removed over a redstribution period and then redistributed to the SINK account.
  • 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.



  • Python3 with Venv
  • At least 1 CELO Gas
  • Access to a Celo node

You may need to install additional build dependencies

$ apt-get install -y autoconf automake build-essential libffi-dev libtool pkg-config python3-dev
$ apt install python3.10-venv


1. Activate a venv


A python virtual environment in a dedicated directory provides a cleaner dependency environment

# Create a new directory at a convenient location
$ mkdir demurrage-voucher
$ cd demurrage-voucher
$ python3 -m venv .venv
$ source .venv/bin/activate

2. Install the Redistributed Demurrage Voucher dependency

# Continue executing these commands in the same "demurrage-voucher" directory
$ pip install erc20-demurrage-token --no-cache

3. Publish a Redistributed Demurrage Voucher onto Celo blockchain


This step assumes you will publish to Celo Alfajores. Modify the params as per your needs.

$ erc20-demurrage-token-publish --name ExampleVoucher --symbol EXMP --decimals 6 --demurrage-level 20000 --redistribution-period 43200 --sink-address 0x000000000000000000000000000000000000dEaD -y keyfile.json --fee-limit 6000000 --fee-price 5000000001 -p -i evm:celo:44787:testnet -s -w -v
  • For more detailed instructions and param descriptions, run "make man" in the cloned repo and browse the man pages.