commit e47720fa04c2ca6abc2e3329981fc6f2cd20e529
parent 399e24764aee27b277bebd28c2dfc88b6b7098fd
Author: nolash <dev@holbrook.no>
Date: Mon, 7 Jun 2021 09:04:17 +0200
Add redistribution single minute demurrage test
Diffstat:
4 files changed, 198 insertions(+), 7 deletions(-)
diff --git a/python/erc20_demurrage_token/sim/sim.py b/python/erc20_demurrage_token/sim/sim.py
@@ -148,10 +148,10 @@ class DemurrageTokenSimulation:
def get_period(self):
return self.period
- def get_demurrage_modifier(self):
+ def get_demurrage(self):
o = self.caller_contract.demurrage_amount(self.address, sender_address=self.caller_address)
r = self.rpc.do(o)
- return float(self.caller_contract.parse_demurrage_amount(r) / (10 ** 38))
+ return float(self.caller_contract.parse_demurrage_amount(r) / (10 ** 40))
def from_units(self, v):
diff --git a/python/examples/sim_noredistribute.py b/python/examples/sim_noredistribute.py
@@ -16,7 +16,7 @@ settings.name = 'Simulated Demurrage Token'
settings.symbol = 'SIM'
settings.decimals = 6
settings.demurrage_level = int(decay_per_minute*(10**40))
-settings.period_minutes = 10800 # 1 week in minutes
+settings.period_minutes = 1 # 1 week in minutes
chain = 'evm:foochain:42'
cap = (10 ** 6) * (10 ** 12)
@@ -55,15 +55,15 @@ period = sim.get_period()
print('start {} now {} period {} minutes passed {}'.format(start, timestamp, period, minutes))
-contract_demurrage = 1 - sim.get_demurrage_modifier() # demurrage in percent (float)
-frontend_demurrage = ((1 - decay_per_minute) ** minutes / 100) # corresponding demurrage modifier (float)
+contract_demurrage = 1 - sim.get_demurrage() # demurrage in percent (float)
+frontend_demurrage = 1.0 - ((1 - decay_per_minute) ** minutes) # corresponding demurrage modifier (float)
demurrage_delta = contract_demurrage - frontend_demurrage # difference between demurrage in contract and demurrage calculated in frontend
alice_checksum = 50000000 - (50000000 * frontend_demurrage) + (200000000 * frontend_demurrage) # alice's balance calculated with frontend demurrage
print("""alice frontend balance {}
alice contract balance {}
-frontend demurrage {}
-contract demurrage {}
+frontend demurrage {:f}
+contract demurrage {:f}
demurrage delta {}""".format(
alice_checksum,
sim.balance(alice),
diff --git a/python/tests/base.py b/python/tests/base.py
@@ -163,3 +163,56 @@ class TestDemurrageCap(TestDemurrage):
self.deploy(c, self.mode)
logg.info('deployed with mode {}'.format(self.mode))
+
+
+
+class TestDemurrageUnit(TestDemurrage):
+
+ def setUp(self):
+ super(TestDemurrage, self).setUp()
+
+ self.tax_level = 50
+ self.period_seconds = 60
+
+ nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
+ self.settings = DemurrageTokenSettings()
+ self.settings.name = 'Foo Token'
+ self.settings.symbol = 'FOO'
+ self.settings.decimals = 6
+ self.settings.demurrage_level = self.tax_level * (10 ** 32)
+ self.settings.period_minutes = int(self.period_seconds/60)
+ self.settings.sink_address = self.accounts[9]
+ self.sink_address = self.settings.sink_address
+
+ o = block_latest()
+ self.start_block = self.rpc.do(o)
+
+ o = block_by_number(self.start_block, include_tx=False)
+ r = self.rpc.do(o)
+
+ try:
+ self.start_time = int(r['timestamp'], 16)
+ except TypeError:
+ self.start_time = int(r['timestamp'])
+
+ self.default_supply = 1000000000000
+ self.default_supply_cap = int(self.default_supply * 10)
+
+ nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
+ c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+
+ self.mode = os.environ.get('ERC20_DEMURRAGE_TOKEN_TEST_MODE')
+ unit_valid_modes = [
+ 'SingleNocap',
+ 'SingleCap',
+ ]
+ if self.mode != None:
+ if self.mode not in unit_valid_modes:
+ raise ValueError('Invalid mode "{}" for "unit" contract tests, valid are {}'.format(self.mode, unit_valid_modes))
+ else:
+ self.mode = 'SingleNocap'
+ logg.debug('executing test setup unit mode {}'.format(self.mode))
+
+ self.deploy(c, self.mode)
+
+ logg.info('deployed with mode {}'.format(self.mode))
diff --git a/python/tests/test_redistribution_unit.py b/python/tests/test_redistribution_unit.py
@@ -0,0 +1,138 @@
+import os
+import unittest
+import json
+import logging
+
+# 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,
+ )
+from chainlib.eth.address import to_checksum_address
+from hexathon import (
+ strip_0x,
+ add_0x,
+ )
+
+# local imports
+from erc20_demurrage_token import DemurrageToken
+
+# test imports
+from tests.base import TestDemurrageUnit
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+testdir = os.path.dirname(__file__)
+
+
+class TestRedistribution(TestDemurrageUnit):
+
+ def test_single_step(self):
+ nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
+ c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+
+ mint_amount = 100000000
+
+ (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], mint_amount)
+ self.rpc.do(o)
+
+ self.backend.time_travel(self.start_time + self.period_seconds)
+
+ (tx_hash, o) = c.change_period(self.address, self.accounts[0])
+ self.rpc.do(o)
+
+ expected_balance = int(mint_amount - ((self.tax_level / 1000000) * mint_amount))
+
+ o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ balance = c.parse_balance_of(r)
+
+ self.assertEqual(balance, expected_balance)
+
+
+ def test_single_step_multi(self):
+ nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
+ c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+
+ mint_amount = 100000000
+
+ for i in range(3):
+ (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[i+1], mint_amount)
+ self.rpc.do(o)
+
+ self.backend.time_travel(self.start_time + self.period_seconds)
+
+ (tx_hash, o) = c.change_period(self.address, self.accounts[0])
+ self.rpc.do(o)
+
+ expected_balance = int(mint_amount - ((self.tax_level / 1000000) * mint_amount))
+
+ for i in range(3):
+ o = c.balance_of(self.address, self.accounts[i+1], sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ balance = c.parse_balance_of(r)
+ self.assertEqual(balance, expected_balance)
+
+
+ def test_single_step_transfer(self):
+ nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
+ c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+
+ mint_amount = 100000000
+ half_mint_amount = int(mint_amount / 2)
+
+ (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], mint_amount)
+ self.rpc.do(o)
+
+ (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[2], mint_amount)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
+ c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[3], half_mint_amount)
+ self.rpc.do(o)
+
+ self.backend.time_travel(self.start_time + self.period_seconds)
+
+ (tx_hash, o) = c.change_period(self.address, self.accounts[1])
+ self.rpc.do(o)
+
+ demurrage_amount = int((self.tax_level / 1000000) * mint_amount)
+
+ expected_balance = mint_amount - demurrage_amount
+ o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ balance = c.parse_balance_of(r)
+ self.assertEqual(balance, expected_balance)
+
+ half_demurrage_amount = int((self.tax_level / 1000000) * half_mint_amount)
+
+ expected_balance = half_mint_amount - half_demurrage_amount
+ o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ balance = c.parse_balance_of(r)
+ self.assertEqual(balance, expected_balance)
+
+ o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ balance = c.parse_balance_of(r)
+ self.assertEqual(balance, expected_balance)
+
+ o = c.total_supply(self.address, sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ supply = c.parse_total_supply(r)
+
+ expected_balance = int(supply * (self.tax_level / 1000000))
+
+ o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ balance = c.parse_balance_of(r)
+ self.assertEqual(balance, expected_balance)
+
+
+if __name__ == '__main__':
+ unittest.main()