erc20-demurrage-token

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

commit c6b5d9a8e08425d46d081e3d013762157a8206c2
parent abe82949ea682357610a87b1de2f6cc90fb3301a
Author: nolash <dev@holbrook.no>
Date:   Mon,  5 Jul 2021 10:26:39 +0200

Move test base to externally importable path

Diffstat:
Apython/erc20_demurrage_token/unittest/__init__.py | 1+
Apython/erc20_demurrage_token/unittest/base.py | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpython/run_tests.sh | 2++
Dpython/tests/base.py | 222-------------------------------------------------------------------------------
Mpython/tests/test_amounts.py | 2+-
Mpython/tests/test_basic.py | 2+-
Mpython/tests/test_cap.py | 2+-
Mpython/tests/test_demurrage_ext.py | 2+-
Mpython/tests/test_growth.py | 2+-
Mpython/tests/test_period.py | 2+-
Mpython/tests/test_redistribution.py | 2+-
Mpython/tests/test_redistribution_unit.py | 2+-
Mpython/tests/test_remainder.py | 2+-
Mpython/tests/test_single.py | 2+-
14 files changed, 265 insertions(+), 232 deletions(-)

diff --git a/python/erc20_demurrage_token/unittest/__init__.py b/python/erc20_demurrage_token/unittest/__init__.py @@ -0,0 +1 @@ +from .base import * diff --git a/python/erc20_demurrage_token/unittest/base.py b/python/erc20_demurrage_token/unittest/base.py @@ -0,0 +1,252 @@ +# standard imports +import logging +import os + +# external imports +from chainlib.eth.unittest.ethtester import EthTesterCase +from chainlib.eth.tx import ( + receipt, + ) +from chainlib.eth.block import ( + block_latest, + block_by_number, + ) +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.constant import ZERO_ADDRESS + +# local imports +from erc20_demurrage_token import ( + DemurrageTokenSettings, + DemurrageToken, + ) + +logg = logging.getLogger() + +#BLOCKTIME = 5 # seconds +TAX_LEVEL = int(10000 * 2) # 2% +# calc "1-(0.98)^(1/518400)" <- 518400 = 30 days of blocks +# 0.00000003897127107225 +#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month +PERIOD = 10 + + +class TestTokenDeploy: + + def __init__(self, rpc, token_symbol='FOO', token_name='Foo Token', sink_address=ZERO_ADDRESS, supply=10**12): + self.tax_level = TAX_LEVEL + self.period_seconds = PERIOD * 60 + + self.settings = DemurrageTokenSettings() + self.settings.name = token_name + self.settings.symbol = token_symbol + self.settings.decimals = 6 + self.settings.demurrage_level = TAX_LEVEL * (10 ** 32) + self.settings.period_minutes = PERIOD + self.settings.sink_address = sink_address + self.sink_address = self.settings.sink_address + + o = block_latest() + self.start_block = rpc.do(o) + + o = block_by_number(self.start_block, include_tx=False) + r = rpc.do(o) + + try: + self.start_time = int(r['timestamp'], 16) + except TypeError: + self.start_time = int(r['timestamp']) + + self.default_supply = supply + self.default_supply_cap = int(self.default_supply * 10) + + + def deploy(self, rpc, deployer_address, interface, mode, supply_cap=10**12): + tx_hash = None + o = None + logg.debug('mode {} {}'.format(mode, self.settings)) + self.mode = mode + if mode == 'MultiNocap': + (tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=True, cap=0) + elif mode == 'SingleNocap': + (tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=0) + elif mode == 'MultiCap': + (tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=True, cap=supply_cap) + elif mode == 'SingleCap': + (tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=supply_cap) + else: + raise ValueError('Invalid mode "{}", valid are {}'.format(mode, DemurrageToken.valid_modes)) + + r = rpc.do(o) + o = receipt(tx_hash) + r = rpc.do(o) + assert r['status'] == 1 + self.start_block = r['block_number'] + self.address = r['contract_address'] + + o = block_by_number(r['block_number']) + r = rpc.do(o) + self.start_time = r['timestamp'] + + return self.address + + +class TestDemurrage(EthTesterCase): + + def setUp(self): + super(TestDemurrage, self).setUp() +# token_deploy = TestTokenDeploy() +# self.settings = token_deploy.settings +# self.sink_address = token_deploy.sink_address +# self.start_block = token_deploy.start_block +# self.start_time = token_deploy.start_time +# self.default_supply = self.default_supply +# self.default_supply_cap = self.default_supply_cap + self.deployer = TestTokenDeploy(self.rpc) + self.default_supply = self.deployer.default_supply + self.default_supply_cap = self.deployer.default_supply_cap + self.start_block = None + self.address = None + self.start_time = None + + + def deploy(self, interface, mode): + self.address = self.deployer.deploy(self.rpc, self.accounts[0], interface, mode, supply_cap=self.default_supply_cap) + self.start_block = self.deployer.start_block + self.start_time = self.deployer.start_time + self.tax_level = self.deployer.tax_level + self.period_seconds = self.deployer.period_seconds + self.sink_address = self.deployer.sink_address + + logg.debug('contract address {} start block {} start time {}'.format(self.address, self.start_block, self.start_time)) + + + def assert_within_lower(self, v, target, tolerance_ppm): + lower_target = target - (target * (tolerance_ppm / 1000000)) + self.assertGreaterEqual(v, lower_target) + self.assertLessEqual(v, target) + logg.debug('asserted within lower {} <= {} <= {}'.format(lower_target, v, target)) + + + def tearDown(self): + pass + + +class TestDemurrageDefault(TestDemurrage): + + def setUp(self): + super(TestDemurrageDefault, self).setUp() + + 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') + if self.mode == None: + self.mode = 'MultiNocap' + logg.debug('executing test setup default mode {}'.format(self.mode)) + + self.deploy(c, self.mode) + + logg.info('deployed with mode {}'.format(self.mode)) + + +class TestDemurrageSingle(TestDemurrage): + + def setUp(self): + super(TestDemurrageSingle, self).setUp() + + 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') + single_valid_modes = [ + 'SingleNocap', + 'SingleCap', + ] + if self.mode != None: + if self.mode not in single_valid_modes: + raise ValueError('Invalid mode "{}" for "single" contract tests, valid are {}'.format(self.mode, single_valid_modes)) + else: + self.mode = 'SingleNocap' + logg.debug('executing test setup demurragesingle mode {}'.format(self.mode)) + + self.deploy(c, self.mode) + + logg.info('deployed with mode {}'.format(self.mode)) + + +class TestDemurrageCap(TestDemurrage): + + def setUp(self): + super(TestDemurrageCap, self).setUp() + + 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') + cap_valid_modes = [ + 'MultiCap', + 'SingleCap', + ] + if self.mode != None: + if self.mode not in cap_valid_modes: + raise ValueError('Invalid mode "{}" for "cap" contract tests, valid are {}'.format(self.mode, cap_valid_modes)) + else: + self.mode = 'MultiCap' + logg.debug('executing test setup demurragecap mode {}'.format(self.mode)) + + 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/run_tests.sh b/python/run_tests.sh @@ -1,5 +1,6 @@ #!/bin/bash +set -x set -e export PYTHONPATH=. @@ -31,3 +32,4 @@ done #done set +e +set +x diff --git a/python/tests/base.py b/python/tests/base.py @@ -1,222 +0,0 @@ -# standard imports -import logging -import os - -# external imports -from chainlib.eth.unittest.ethtester import EthTesterCase -from chainlib.eth.tx import ( - receipt, - ) -from chainlib.eth.block import ( - block_latest, - block_by_number, - ) -from chainlib.eth.nonce import RPCNonceOracle - -# local imports -from erc20_demurrage_token import ( - DemurrageTokenSettings, - DemurrageToken, - ) - -logg = logging.getLogger() - -#BLOCKTIME = 5 # seconds -TAX_LEVEL = int(10000 * 2) # 2% -# calc "1-(0.98)^(1/518400)" <- 518400 = 30 days of blocks -# 0.00000003897127107225 -#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month -PERIOD = 10 - - -class TestDemurrage(EthTesterCase): - - def setUp(self): - super(TestDemurrage, self).setUp() - - self.tax_level = TAX_LEVEL - self.period_seconds = PERIOD * 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 = TAX_LEVEL * (10 ** 32) - self.settings.period_minutes = PERIOD - 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 = 10 ** 12 - self.default_supply_cap = int(self.default_supply * 10) - - - def deploy(self, interface, mode): - tx_hash = None - o = None - if mode == 'MultiNocap': - (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=True, cap=0) - elif mode == 'SingleNocap': - (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=0) - elif mode == 'MultiCap': - (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=True, cap=self.default_supply_cap) - elif mode == 'SingleCap': - (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=self.default_supply_cap) - else: - raise ValueError('Invalid mode "{}", valid are {}'.format(self.mode, DemurrageToken.valid_modes)) - - r = self.rpc.do(o) - o = receipt(tx_hash) - r = self.rpc.do(o) - self.assertEqual(r['status'], 1) - self.start_block = r['block_number'] - self.address = r['contract_address'] - - o = block_by_number(r['block_number']) - r = self.rpc.do(o) - self.start_time = r['timestamp'] - - logg.debug('contract address {} start block {} start time {}'.format(self.address, self.start_block, self.start_time)) - - - def assert_within_lower(self, v, target, tolerance_ppm): - lower_target = target - (target * (tolerance_ppm / 1000000)) - self.assertGreaterEqual(v, lower_target) - self.assertLessEqual(v, target) - logg.debug('asserted within lower {} <= {} <= {}'.format(lower_target, v, target)) - - - def tearDown(self): - pass - - -class TestDemurrageDefault(TestDemurrage): - - def setUp(self): - super(TestDemurrageDefault, self).setUp() - - 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') - if self.mode == None: - self.mode = 'MultiNocap' - logg.debug('executing test setup default mode {}'.format(self.mode)) - - self.deploy(c, self.mode) - - logg.info('deployed with mode {}'.format(self.mode)) - - -class TestDemurrageSingle(TestDemurrage): - - def setUp(self): - super(TestDemurrageSingle, self).setUp() - - 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') - single_valid_modes = [ - 'SingleNocap', - 'SingleCap', - ] - if self.mode != None: - if self.mode not in single_valid_modes: - raise ValueError('Invalid mode "{}" for "single" contract tests, valid are {}'.format(self.mode, single_valid_modes)) - else: - self.mode = 'SingleNocap' - logg.debug('executing test setup demurragesingle mode {}'.format(self.mode)) - - self.deploy(c, self.mode) - - logg.info('deployed with mode {}'.format(self.mode)) - - -class TestDemurrageCap(TestDemurrage): - - def setUp(self): - super(TestDemurrageCap, self).setUp() - - 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') - cap_valid_modes = [ - 'MultiCap', - 'SingleCap', - ] - if self.mode != None: - if self.mode not in cap_valid_modes: - raise ValueError('Invalid mode "{}" for "cap" contract tests, valid are {}'.format(self.mode, cap_valid_modes)) - else: - self.mode = 'MultiCap' - logg.debug('executing test setup demurragecap mode {}'.format(self.mode)) - - 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_amounts.py b/python/tests/test_amounts.py @@ -13,7 +13,7 @@ from chainlib.eth.tx import receipt from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageDefault +from erc20_demurrage_token.unittest.base import TestDemurrageDefault logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_basic.py b/python/tests/test_basic.py @@ -18,7 +18,7 @@ from chainlib.eth.block import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageDefault +from erc20_demurrage_token.unittest.base import TestDemurrageDefault logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_cap.py b/python/tests/test_cap.py @@ -18,7 +18,7 @@ from hexathon import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageCap +from erc20_demurrage_token.unittest.base import TestDemurrageCap logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_demurrage_ext.py b/python/tests/test_demurrage_ext.py @@ -10,7 +10,7 @@ from erc20_demurrage_token import DemurrageToken from erc20_demurrage_token.demurrage import DemurrageCalculator # test imports -from tests.base import TestDemurrage +from erc20_demurrage_token.unittest.base import TestDemurrage class TestEmulate(TestDemurrage): diff --git a/python/tests/test_growth.py b/python/tests/test_growth.py @@ -18,7 +18,7 @@ from chainlib.eth.block import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageDefault +from erc20_demurrage_token.unittest.base import TestDemurrageDefault logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_period.py b/python/tests/test_period.py @@ -13,7 +13,7 @@ from chainlib.eth.tx import receipt from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageDefault +from erc20_demurrage_token.unittest.base import TestDemurrageDefault logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_redistribution.py b/python/tests/test_redistribution.py @@ -22,7 +22,7 @@ from hexathon import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageDefault +from erc20_demurrage_token.unittest.base import TestDemurrageDefault logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_redistribution_unit.py b/python/tests/test_redistribution_unit.py @@ -21,7 +21,7 @@ from hexathon import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageUnit +from erc20_demurrage_token.unittest.base import TestDemurrageUnit logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_remainder.py b/python/tests/test_remainder.py @@ -16,7 +16,7 @@ import eth_tester from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageDefault +from erc20_demurrage_token.unittest.base import TestDemurrageDefault logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/python/tests/test_single.py b/python/tests/test_single.py @@ -18,7 +18,7 @@ from hexathon import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageSingle +from erc20_demurrage_token.unittest.base import TestDemurrageSingle logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger()