erc20-demurrage-token

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

README.md (12414B)


      1 # Overview
      2 
      3     de-mur-rage
      4 
      5     1: the detention of a ship by the freighter beyond the time allowed for loading, unloading, or sailing
      6 
      7     2: a charge for detaining a ship, freight car, or truck
      8 
      9 This ERC20 smart contract implementation for the EVM imposes a demurrage
     10 on all held token balances.
     11 
     12 The demurrage is a continuous value *decay*, subtracted from all
     13 balances every minute.
     14 
     15 Also. a time period is defined at contract creation time at which the
     16 difference between held balances and the demurrage can be withdrawn to a
     17 pre-selected address, which in turn can redistribute that token value.
     18 
     19 In short: Everyone is taxed a little something every minute, and every
     20 so often a decision is made on how to redistribute that tax.
     21 
     22 ## Features
     23 
     24 - Continuous decay of all balances.
     25 
     26 - Capture and redistribution of decayed balances.
     27 
     28 - Per-minute decay resolution.
     29 
     30 - Minting and burning of vouchers.
     31 
     32 - Grant and revoke access to mint and burn vouchers.
     33 
     34 - Voucher expiration (modifiable anytime after publishing).
     35 
     36 - Supply cap (modifiable anytime after publishing).
     37 
     38 - Constant gas usage across exponential calculations.
     39 
     40 ## Nomenclature
     41 
     42 ‘`Demurrage`’  
     43 A percentage of token supply that will continuously be removed.
     44 
     45 ‘`Demurrage Period`’  
     46 A period of time denominated in minutes after which demurraged amounts
     47 are available for redistribution.
     48 
     49 ‘`Sink Account`’  
     50 The intermediate beneficiary of the demurraged amount, which may or may
     51 not redistribute value.
     52 
     53 ‘`Base balance`’  
     54 The inflated balance of each used which is stored for bookkeeping.
     55 
     56 # Use Case
     57 
     58 The use-case inspiring this implementation is in the context of issuance
     59 of a *voucher* representing a credit obligation of an *Issuer* or
     60 *Association of Issuers*.
     61 
     62 This voucher can be redeemed as payment for the products of the Issuer.
     63 
     64 The Issuer is the entity legally obligated to redeem the voucher as
     65 payment.
     66 
     67 Introducing demurrage on this vehicle discourages *withholding* the
     68 voucher, for example for speculative advantage.
     69 
     70 This also encourages increased *velocity* of voucher use.
     71 
     72 ## Example
     73 
     74 Given:
     75 
     76 - 10 voucher holders.
     77 
     78 - A total supply of 1000 tokens.
     79 
     80 - Demurrage of 2% per 30 days (43200 minutes).
     81 
     82 - Redistribution period of 30 days (43200 minutes).
     83 
     84 If no trades are made, the resulting balances after one redistribution
     85 period of every user would be 98 Vouchers.
     86 
     87 The Sink Address will have a balance of 20 vouchers after the same
     88 period.
     89 
     90 Note that after the redistribution the total of all balances will equal
     91 the total minted amount.
     92 
     93 Note that all accounts holding such vouchers are effected by demurrage
     94 (even the Sink Account, pending redistribution).
     95 
     96 # Smart contract
     97 
     98 ## Common interfaces
     99 
    100 The smart contract is written in solidity, compatible with 0.8.x.
    101 
    102 It implements a number of interfaces both from the Ethereum (ERC)
    103 standards aswell as the Community Inclusion Currency contract interface
    104 suite.
    105 
    106 ### ERC standard interfaces
    107 
    108 - [ERC20 - Token Standard](https://eips.ethereum.org/EIPS/eip-20)
    109 
    110 - [ERC165 - Standard Interface
    111   Detection](https://eips.ethereum.org/EIPS/eip-165)
    112 
    113 - [ERC173 - Contract Ownership
    114   Standard](https://eips.ethereum.org/EIPS/eip-173)
    115 
    116 - [ERC5679 - Token Minting and Burning (as part of CIC.Minter and
    117   CIC.Burner)](https://eips.ethereum.org/EIPS/eip-5679)
    118 
    119 ### CIC interfaces
    120 
    121 - [Burner](https://git.grassecon.net/cicnet/cic-contracts/src/branch/master/solidity/Burner.sol)
    122 
    123 - [Expire](https://git.grassecon.net/cicnet/cic-contracts/src/branch/master/solidity/Expire.sol)
    124 
    125 - [Minter](https://git.grassecon.net/cicnet/cic-contracts/src/branch/master/solidity/Minter.sol)
    126 
    127 - [Seal](https://git.grassecon.net/cicnet/cic-contracts/src/branch/master/solidity/Seal.sol)
    128 
    129 - [Writer](https://git.grassecon.net/cicnet/cic-contracts/src/branch/master/solidity/Writer.sol)
    130 
    131 ## Dependencies
    132 
    133 The token contract uses the
    134 [ADBKMath](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol)
    135 library to calculate exponentials.
    136 
    137 ## Permissions
    138 
    139 The smart contract defines three levels of access.
    140 
    141 1.  Voucher contract owner
    142 
    143 2.  Voucher minter
    144 
    145 3.  Voucher holder
    146 
    147 ### Contract owner
    148 
    149 When the contract is published to the network, the signer account of the
    150 publishing transaction will be the contract owner.
    151 
    152 Contract ownership can be changed by the owner using the **ERC173**
    153 standard interface.
    154 
    155 ### Minter
    156 
    157 A minter has access to mint vouchers, and to burn vouchers from its own
    158 balance.
    159 
    160 Only the contract owner may mint, and may add and remove minters.
    161 Minters may be added and removed using the **CIC Writer** interface, as
    162 long as the `WRITER_STATE` seal is not set. See [Sealing the
    163 contract](#seal_005fstate) for further details.
    164 
    165 The contract owner is automatically a minter.
    166 
    167 ### Holder
    168 
    169 Any address may hold vouchers, and transfer vouchers from their balance.
    170 
    171 Minters and the contract owner are automatically token holders.
    172 
    173 All token holders are subject to demurrage.
    174 
    175 ## Publishing the contract
    176 
    177 The contract is published with the following arguments:
    178 
    179 ‘`name`’  
    180 ERC20 voucher name
    181 
    182 ‘`symbol`’  
    183 ERC20 voucher symbol
    184 
    185 ‘`decimals`’  
    186 ERC20 decimal count
    187 
    188 ‘`decayLevel`’  
    189 Level of decay per minute. See [Specifying
    190 demurrage](#specifying_005fdemurrage) below for further details.
    191 
    192 ‘`periodMinutes`’  
    193 Number of minutes between each time the demurraged value can be
    194 withdrawn to the *Sink Account*. See [Withdrawing demurraged
    195 value](#withdrawing) below for further details. The period may not be
    196 altered.
    197 
    198 ‘`defaultSinkAddress`’  
    199 The initial *Sink Address*. The address may be altered as long as the
    200 `SINK_STATE` seal has not been set. See [Sealing the
    201 contract](#seal_005fstate) for further details.
    202 
    203 ### Specifying demurrage
    204 
    205 The *input parameter* to the contract is a 128-bit positive fixed-point
    206 number, where the most significant 64 bits represent the integer part,
    207 and the lower 64 bits represents the decimals part, each consecutive
    208 lesser bit halving the value of the previous bit.
    209 
    210 For example, The byte value `00000000 00000002 a0000000 00000000`,
    211 representing a zero-stripped binary value of $10.101$. This translates
    212 to the (base 10) decimal value $2.625$. The decimal part is calculated
    213 as, from left to right: $(1 * 0.5) + (0 * 0.25) + (1 * 0.125)$.
    214 
    215 #### Calculating the demurrage parameter
    216 
    217 The minute granularity of the demurrage value is calculating using the
    218 continuous decay function.
    219 
    220 For example, for a demurrage of 2% per 30 days (43200 minutes), the
    221 input value will be:
    222 
    223 $(1-0.02)^(1/43200) ~ 0.99999953234484737109$
    224 
    225 The decimal part of the fixed-point representation of this value is:
    226 
    227 `fffff8276fb8cfff`
    228 
    229 The input parameter becomes:
    230 
    231 `0000000000000000ffffa957014dc7ff`
    232 
    233 See [Tools](#tools) for additional help generating the necessary values.
    234 
    235 Note that attempting to publish a voucher contract with no (zero)
    236 demurrage will fail (if demurrage is not needed, use another contract).
    237 
    238 ## Using the contract
    239 
    240 ### Withdrawing demurrage
    241 
    242 After each redistribution period, the demurraged value of that period
    243 can be withdrawn to the currently defined *Sink Account*.
    244 
    245 The demurrage is calculated as from the total supply of voucher at the
    246 end of the period.
    247 
    248 Withdrawal should happen implicitly duing normal operation of the
    249 contract. See [Side-effects in state changes](#sideeffects).
    250 
    251 To explicitly credit the *Sink Address* with the demurrage value after a
    252 period has been exceeded, the `changePeriod()` (`8f1df6bc`) method can
    253 be called.
    254 
    255 ### Setting voucher expiry
    256 
    257 The effect of a voucher expiring is that all balances will be frozen,
    258 and all state changes affecting token balances will be blocked.
    259 
    260 Expiry is defined in terms of redistribution periods. For example, if
    261 the redistribution period is 30 days, and the expity is 3, then the
    262 voucher expires after 90 days.
    263 
    264 The expiry takes effect immediately when the redistribution period time
    265 has been exceeded.
    266 
    267 When the contract is published, no expiry is set.
    268 
    269 Expiry may be set after publishing using the `CIC.Expire` interface.
    270 
    271 If the `EXPIRE_STATE` seal has been set, expiry may not be changed
    272 further.
    273 
    274 ### Capping voucher supply
    275 
    276 The effect of a voucher supply cap is that all `CIC.Minter` calls will
    277 fail if the total supply after minting exceeds the defined supply cap.
    278 
    279 The supply cap still allows vouchers to be minted after `CIC.Burn`
    280 calls, provided that the previous condition holds.
    281 
    282 To apply the supply cap, the method `setMaxSupply(uint256) (6f8b44b0)`
    283 is used.
    284 
    285 ### Side-effects in state changes
    286 
    287 All state changes involving voucher values implicitly execute two core
    288 methods to ensure application of the demurrage and redistribution.
    289 
    290 The two methods are:
    291 
    292 `applyDemurrage() (731f237c)`  
    293 Calculates the demurrage modifier of all balances according to the
    294 current timestamp.
    295 
    296 `changePeriod() (8f1df6bc)`  
    297 If the previously executed period change does not match the current
    298 period, the period is changed, and the *Sink Address* is credited with
    299 the demurrage amount of the current total supply.
    300 
    301 Both of these methods are *noop* if no demurrage or withdrawal is
    302 pending, respectively.
    303 
    304 Examples of state changes that execute these methods include
    305 `ERC20.transfer(...)`, `ERC20.transferFrom(...)` and `CIC.mintTo(...)`.
    306 
    307 ### Sealing the contract
    308 
    309 Certain mutable core parameters of the contract can be *sealed*, meaning
    310 prevented from being modifier further.
    311 
    312 Sealing is executed using the `CIC.Seal` interface.
    313 
    314 The sealing of parameters is irreversible.
    315 
    316 The sealable parameters are[^1]:
    317 
    318 `WRITER_STATE`  
    319 The `CIC.Writer` interface is blocked. The effect of this is that no
    320 more changes may be made to which accounts have minter permission.
    321 
    322 `SINK_STATE`  
    323 After setting this seal, the *Sink Address* may not be changed.
    324 
    325 `EXPIRY_STATE`  
    326 Prevents future changes to the voucher expiry date[^2].
    327 
    328 `CAP_STATE`  
    329 Immediately prevents future voucher minting, regardless of permissions.
    330 
    331 ## Gas usage
    332 
    333 Gas usage is constant regardless of the amount of time passed between
    334 each execution of demurrage and redistribution period calculations.
    335 
    336 ## Caveats
    337 
    338 A `ERC20.transferFrom(...)` following an `ERC20.approve(...)` call, when
    339 called across period thresholds, may fail if margin to demurraged amount
    340 is insufficient.
    341 
    342 # Tools
    343 
    344 When installed as a python package, `erc20-demurrage-token` installs the
    345 `erc20-demurrage-token-publish` executable script, which can be used to
    346 publish smart contract instances.
    347 
    348 While the man page for the tool can be referred to for general
    349 information of the tool usage, two argument flags warrant special
    350 mention in the context of this documentation.
    351 
    352 `--demurrage-level`  
    353 The percentage of demurrage in terms of the redistribution period,
    354 defined as parts-per-million.
    355 
    356 `--redistribution-period`  
    357 A numeric value denominated in *minutes* to define the redistribution
    358 period of the voucher demurrage.
    359 
    360 For example, to define a 2% demurrage value for a redistribution period
    361 of 30 days (43200 minutes), the argument to the argument flags would be:
    362 
    363     erc20-demurrage-token-publish --demurrage-level 20000 --redistribution-period 43200 ...
    364 
    365 ## Calculating fixed-point values
    366 
    367 The `erc20-demurrage-token` package installs the python package `dexif`
    368 as part of its dependencies.
    369 
    370 This package in turn provides an epinymous command-line tool (`dexif`)
    371 which converts decimal values to a 128-bit fixed-point value expected by
    372 the contract constructor.
    373 
    374 An example:
    375 
    376     $ dexif 123.456
    377     7b74bc6a7ef9db23ff
    378 
    379     $ dexif -x 7b74bc6a7ef9db23ff
    380     123.456
    381 
    382 ## Contract interaction with chainlib-eth
    383 
    384 All smart contract tests are implementing using
    385 [chainlib-eth](https://git.defalsify.org/chainlib-eth) from the
    386 chaintool suite.
    387 
    388 The `eth-encode` tool from the `chainlib-eth` python package may be a
    389 convenient way to interact with contract features.
    390 
    391 Some examples include:
    392 
    393     # explicitly call changePeriod()
    394     $ eth-encode --mode tx --signature changePeriod -e <contract_address> -y <key_file> ...
    395 
    396     # Set the sink address seal (The integer value of the SINK_STATE flag is 2 at the time of writing)
    397     $ eth-encode --mode tx --signature seal  -e <contract_address> -y <key_file> ... u:2
    398 
    399     # Query current sink address of contract
    400     $ eth-encode --mode call --signature sinkAddress -e <contract_address> ...
    401 
    402 [^1]: Please refer to the contract source code for the numeric values of
    403     the state flags
    404 
    405 [^2]: The `EXPIRY_STATE` is implicitly set after expiration.