Add growth decay test, improve resolution in growth/decay in contract (SingleCap)

This commit is contained in:
nolash 2021-06-08 07:38:10 +02:00
parent 1b1419c03b
commit e8781a9aa0
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
7 changed files with 327 additions and 211 deletions

File diff suppressed because one or more lines are too long

View File

@ -323,6 +323,40 @@ class DemurrageToken(ERC20):
return self.call_noarg('supplyCap', contract_address, sender_address=sender_address) return self.call_noarg('supplyCap', contract_address, sender_address=sender_address)
def grow_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('growBy')
enc.typ(ABIContractType.UINT256)
enc.typ(ABIContractType.UINT256)
enc.uint256(value)
enc.uint256(period)
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
return o
def decay_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('decayBy')
enc.typ(ABIContractType.UINT256)
enc.typ(ABIContractType.UINT256)
enc.uint256(value)
enc.uint256(period)
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
return o
@classmethod @classmethod
def parse_actual_period(self, v): def parse_actual_period(self, v):
return abi_decode_single(ABIContractType.UINT256, v) return abi_decode_single(ABIContractType.UINT256, v)
@ -376,3 +410,12 @@ class DemurrageToken(ERC20):
@classmethod @classmethod
def parse_supply_cap(self, v): def parse_supply_cap(self, v):
return abi_decode_single(ABIContractType.UINT256, v) return abi_decode_single(ABIContractType.UINT256, v)
@classmethod
def parse_grow_by(self, v):
return abi_decode_single(ABIContractType.UINT256, v)
@classmethod
def parse_decay_by(self, v):
return abi_decode_single(ABIContractType.UINT256, v)

View File

@ -17,7 +17,7 @@ settings.symbol = 'SIM'
settings.decimals = 6 settings.decimals = 6
settings.demurrage_level = int(decay_per_minute*(10**38)) settings.demurrage_level = int(decay_per_minute*(10**38))
#settings.period_minutes = 1 # 1 week in minutes #settings.period_minutes = 1 # 1 week in minutes
settings.period_minutes = 60*24*7*4 settings.period_minutes = 60*24*7
chain = 'evm:foochain:42' chain = 'evm:foochain:42'
cap = (10 ** 6) * (10 ** 12) cap = (10 ** 6) * (10 ** 12)

View File

@ -8,6 +8,7 @@ modes=(MultiNocap MultiCap SingleCap SingleNocap)
for m in ${modes[@]}; do for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_basic.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_basic.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_growth.py
done done
modes=(MultiCap SingleCap) modes=(MultiCap SingleCap)

View File

@ -28,30 +28,30 @@ testdir = os.path.dirname(__file__)
class TestBasic(TestDemurrageDefault): class TestBasic(TestDemurrageDefault):
def test_hello(self): # def test_hello(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
o = c.actual_period(self.address, sender_address=self.accounts[0]) # o = c.actual_period(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
#
self.backend.time_travel(self.start_time + self.period_seconds + 1) # self.backend.time_travel(self.start_time + self.period_seconds + 1)
o = c.actual_period(self.address, sender_address=self.accounts[0]) # o = c.actual_period(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
#
#
def test_balance(self): # def test_balance(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
r = self.rpc.do(o) # r = self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 1024) # self.assertEqual(balance, 1024)
def test_apply_demurrage(self): def test_apply_demurrage(self):
@ -115,179 +115,179 @@ class TestBasic(TestDemurrageDefault):
self.assertLessEqual(modifier, demurrage_amount_truncate) self.assertLessEqual(modifier, demurrage_amount_truncate)
def test_mint(self): # def test_mint(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
r = self.rpc.do(o) # r = self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 1024) # self.assertEqual(balance, 1024)
#
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 976) # (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 976)
r = self.rpc.do(o) # r = self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 2000) # self.assertEqual(balance, 2000)
#
#
self.backend.time_travel(self.start_time + 61) # self.backend.time_travel(self.start_time + 61)
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0]) # (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, int(2000 * 0.98)) # self.assertEqual(balance, int(2000 * 0.98))
#
#
def test_minter_control(self): # def test_minter_control(self):
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
#
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 0) # self.assertEqual(r['status'], 0)
#
(tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[1]) # (tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[1])
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 0) # self.assertEqual(r['status'], 0)
#
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[1]) # (tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[1])
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
(tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[2]) # (tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[2])
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 0) # self.assertEqual(r['status'], 0)
#
(tx_hash, o) = c.remove_minter(self.address, self.accounts[1], self.accounts[1]) # (tx_hash, o) = c.remove_minter(self.address, self.accounts[1], self.accounts[1])
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 0) # self.assertEqual(r['status'], 0)
#
#
def test_base_amount(self): # def test_base_amount(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
#
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
self.rpc.do(o) # self.rpc.do(o)
#
self.backend.time_travel(self.start_time + 61) # self.backend.time_travel(self.start_time + 61)
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0]) # (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
o = c.to_base_amount(self.address, 1000, sender_address=self.accounts[0]) # o = c.to_base_amount(self.address, 1000, sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
amount = c.parse_to_base_amount(r) # amount = c.parse_to_base_amount(r)
self.assertEqual(amount, 1020) # self.assertEqual(amount, 1020)
#
#
def test_transfer(self): # def test_transfer(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
#
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
self.rpc.do(o) # self.rpc.do(o)
#
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[2], 500) # (tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[2], 500)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 524) # self.assertEqual(balance, 524)
#
o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 500) # self.assertEqual(balance, 500)
#
nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.transfer(self.address, self.accounts[2], self.accounts[1], 500) # (tx_hash, o) = c.transfer(self.address, self.accounts[2], self.accounts[1], 500)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
#
#
def test_transfer_from(self): # def test_transfer_from(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024) # (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
self.rpc.do(o) # self.rpc.do(o)
#
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.approve(self.address, self.accounts[1], self.accounts[2], 500) # (tx_hash, o) = c.approve(self.address, self.accounts[1], self.accounts[2], 500)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 1024) # self.assertEqual(balance, 1024)
#
nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc) # nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) # c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.transfer_from(self.address, self.accounts[2], self.accounts[1], self.accounts[3], 500) # (tx_hash, o) = c.transfer_from(self.address, self.accounts[2], self.accounts[1], self.accounts[3], 500)
self.rpc.do(o) # self.rpc.do(o)
o = receipt(tx_hash) # o = receipt(tx_hash)
r = self.rpc.do(o) # r = self.rpc.do(o)
self.assertEqual(r['status'], 1) # self.assertEqual(r['status'], 1)
#
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 524) # self.assertEqual(balance, 524)
#
o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0]) # o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
r = self.rpc.do(o) # r = self.rpc.do(o)
balance = c.parse_balance_of(r) # balance = c.parse_balance_of(r)
self.assertEqual(balance, 500) # self.assertEqual(balance, 500)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -0,0 +1,70 @@
# standard imports
import os
import unittest
import json
import logging
import datetime
# external imports
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.block import (
block_latest,
block_by_number,
)
# local imports
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
testdir = os.path.dirname(__file__)
class TestGrowth(TestDemurrageDefault):
def test_grow_by(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
growth_factor = (1000000 + self.tax_level) / 1000000
v = 1000000000
o = c.grow_by(self.address, v, 1, sender_address=self.accounts[0])
r = self.rpc.do(o)
g = c.parse_grow_by(r)
self.assertEqual(int(v * growth_factor), g)
period = 10
growth_factor = (1 + (self.tax_level) / 1000000) ** period
o = c.grow_by(self.address, v, period, sender_address=self.accounts[0])
r = self.rpc.do(o)
g = c.parse_grow_by(r)
self.assertEqual(int(v * growth_factor), g)
def test_decay_by(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
growth_factor = (1000000 - self.tax_level) / 1000000
v = 1000000000
o = c.decay_by(self.address, v, 1, sender_address=self.accounts[0])
r = self.rpc.do(o)
g = c.parse_decay_by(r)
self.assertEqual(int(v * growth_factor), g)
period = 10
growth_factor = (1 - (self.tax_level) / 1000000) ** period
o = c.decay_by(self.address, v, period, sender_address=self.accounts[0])
r = self.rpc.do(o)
g = c.parse_decay_by(r)
self.assertEqual(int(v * growth_factor), g)
if __name__ == '__main__':
unittest.main()

View File

@ -52,6 +52,9 @@ contract DemurrageTokenSingleCap {
// (this constant x 1000000 is contained within 128 bits) // (this constant x 1000000 is contained within 128 bits)
uint256 constant nanoDivider = 100000000000000000000000000; // now nanodivider, 6 zeros less uint256 constant nanoDivider = 100000000000000000000000000; // now nanodivider, 6 zeros less
// remaining decimal positions of nanoDivider to reach 38, equals precision in growth and decay
uint256 constant growthResolutionFactor = 1000000000000;
// Timestamp of start of periods (time which contract constructor was called) // Timestamp of start of periods (time which contract constructor was called)
uint256 public immutable periodStart; uint256 public immutable periodStart;
@ -60,7 +63,7 @@ contract DemurrageTokenSingleCap {
// Demurrage in ppm per minute // Demurrage in ppm per minute
uint256 public immutable taxLevel; uint256 public immutable taxLevel;
// Addresses allowed to mint new tokens // Addresses allowed to mint new tokens
mapping (address => bool) minter; mapping (address => bool) minter;
@ -271,7 +274,7 @@ contract DemurrageTokenSingleCap {
} }
function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) { function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
return _supply * (nanoDivider - (_demurrageAmount / 1000000000000)); return _supply * (nanoDivider - (_demurrageAmount / nanoDivider));
} }
// Returns the amount sent to the sink address // Returns the amount sent to the sink address
@ -364,33 +367,32 @@ contract DemurrageTokenSingleCap {
uint256 valueFactor; uint256 valueFactor;
uint256 truncatedTaxLevel; uint256 truncatedTaxLevel;
valueFactor = 1000000; valueFactor = growthResolutionFactor;
truncatedTaxLevel = taxLevel / (nanoDivider * 1000000); truncatedTaxLevel = taxLevel / nanoDivider;
for (uint256 i = 0; i < _period; i++) { for (uint256 i = 0; i < _period; i++) {
valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / 1000000); valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
} }
return (valueFactor * _value) / 1000000; return (valueFactor * _value) / growthResolutionFactor;
} }
// Calculate a value reduced by demurrage by the given period // Calculate a value reduced by demurrage by the given period
// TODO: higher precision if possible
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) { function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {
uint256 valueFactor; uint256 valueFactor;
uint256 truncatedTaxLevel; uint256 truncatedTaxLevel;
valueFactor = 1000000; valueFactor = growthResolutionFactor;
truncatedTaxLevel = taxLevel / (nanoDivider * 1000000); truncatedTaxLevel = taxLevel / nanoDivider;
for (uint256 i = 0; i < _period; i++) { for (uint256 i = 0; i < _period; i++) {
valueFactor = valueFactor - ((valueFactor * truncatedTaxLevel) / 1000000); valueFactor = valueFactor - ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
} }
return (valueFactor * _value) / 1000000; return (valueFactor * _value) / growthResolutionFactor;
} }
// Inflates the given amount according to the current demurrage modifier // Inflates the given amount according to the current demurrage modifier
function toBaseAmount(uint256 _value) public view returns (uint256) { function toBaseAmount(uint256 _value) public view returns (uint256) {
return (_value * nanoDivider * 1000000000000) / demurrageAmount; return (_value * nanoDivider * growthResolutionFactor) / demurrageAmount;
} }
// Implements ERC20, triggers tax and/or redistribution // Implements ERC20, triggers tax and/or redistribution