erc20-demurrage-token

ERC20 token with redistributed continual demurrage
Log | Files | Refs | README

commit f75472fcf5f460f5743ffd844df9bea7cae4ab3c
parent 65a91cc44d7062e24deb14f541109404b8b9bd13
Author: lash <dev@holbrook.no>
Date:   Wed,  1 Mar 2023 12:01:32 +0000

Update readme for calculations and inputs

Diffstat:
MREADME.md | 94++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msolidity/DemurrageTokenSingleNocap.sol | 3---
2 files changed, 53 insertions(+), 44 deletions(-)

diff --git a/README.md b/README.md @@ -32,63 +32,75 @@ ## Mint -* 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 +* Minters are called writers. Contract owner can add and remove writers. +* A writer can remove itself +* The interface says the amount and is at the caller's discretion per contract call. _validation_ is outside of this contract. +* Writers can mint any amount. If supply cap is set, minting will be limited to this cap. -## Demurrage -* 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` +## Input parameters + +The redistrbution period is passed to the contract in minutes. E.g. a redistribution period of one month would be approximately 43200 minutes. + +The demurrage level specified as the percentage of continuous growth per minute: + +`(1 - percentage) ^ (1 / period)` + +E.g. A demurrage of 2% monthly would be defined as: + +`(1 - 0.02) ^ (1 / 43200) ~ 0.99999953234484737109` + +The number must be provided to the contract as a 64x64 bit fixed-point number (where the integer part is 0). + +A script is included in the python package to publish the contract which takes the input as a percentage as parts-per-million and converts the correct input argument for the contract. The calculation can be found in the function `process_config_local` in `python/erc20_demurrage_token/runnable/publish.py`. It uses the python module [dexif](https://pypi.org/project/dexif/) to perform the fixed-point conversion. + + +## Demurrage calculation + +The demurrage calculation inside the contract is done by the following formula, where `demurrageLevel` is the demurrage level input parameter of the contract: + +`newDemurrageModifier = currentDemurrageModifier * (e ^ (ln(demurrageLevel) * minutes))` + +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. + + +All client-facing values (_balance output_ , _transfer inputs_) are adjusted with `demurrageModifier`. + +e.g. `_balance output_ = user_balance - user_balance * demurrageModifier` ## Redistribution * 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. +* 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. +* Redistributed tokens are added to the balance of the _sink address_ given when the contract is published. +* _sink address_ may be changed. -## Data structures +## Data representation -* 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 +Token parameters are truncated when calculating demurrage and redistribution: -### Notes +* Redistribution period: 32 bits +* Token supply: 72 bits +* Demurrage modifier: 64 bits -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. + + +## Gas usage + +The token contract uses the [ADBKMath](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol) library to calculate exponentials. + +Gas usage is constant regardless of the amount of time passed between each execution of demurrage and redistribution period calculations. ## QA -* Basic python tests in place -* How to determine and generate sufficient test vectors, and how to adapt them to scripts. -* Audit sources? +* Tests are implemented using the `chaintool` python package suite. + ## Known issues diff --git a/solidity/DemurrageTokenSingleNocap.sol b/solidity/DemurrageTokenSingleNocap.sol @@ -706,9 +706,6 @@ contract DemurrageTokenSingleNocap { if (_sum == 0x9493f8b2) { // EIP173 return true; } - if (_sum == 0x37a47be4) { // OwnedAccepter - return true; - } return false; } }