erc20-demurrage-token

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

commit e142dd043282c3c52b873d7be492ff89bd0fdf60
parent 64621ca9b3411753e8015ffec4f2e315b46a849f
Author: nolash <dev@holbrook.no>
Date:   Sat,  5 Jun 2021 19:19:17 +0200

Add transfer, mint, balance to sim

Diffstat:
Apython/config/eth.ini | 2++
Apython/config/session.ini | 2++
Apython/config/token.ini | 8++++++++
Mpython/erc20_demurrage_token/sim/sim.py | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mpython/tests/sim/tests_sim.py | 20++++++++++++++++----
5 files changed, 129 insertions(+), 6 deletions(-)

diff --git a/python/config/eth.ini b/python/config/eth.ini @@ -0,0 +1,2 @@ +[eth] +provider=http://localhost:8545 diff --git a/python/config/session.ini b/python/config/session.ini @@ -0,0 +1,2 @@ +[session] +chain_spec= diff --git a/python/config/token.ini b/python/config/token.ini @@ -0,0 +1,8 @@ +[token] +redistribution_period=10800 +demurrage_level=50 +supply_limit=0 +symbol=RDT +name=Redistributed Demurraged Token +decimals=6 +sink_address= diff --git a/python/erc20_demurrage_token/sim/sim.py b/python/erc20_demurrage_token/sim/sim.py @@ -1,9 +1,23 @@ +# standard imports +import logging + # external imports from chainlib.eth.unittest.ethtester import create_tester_signer from chainlib.eth.unittest.base import TestRPCConnection -from chainlib.eth.tx import receipt +from chainlib.eth.tx import ( + receipt, + Tx, + ) from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.gas import ( + OverrideGasOracle, + Gas, + ) from chainlib.eth.address import to_checksum_address +from chainlib.eth.block import ( + block_latest, + block_by_number, + ) from crypto_dev_signer.keystore.dict import DictKeystore from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from hexathon import ( @@ -14,14 +28,19 @@ from hexathon import ( # local imports from erc20_demurrage_token import DemurrageToken +logg = logging.getLogger(__name__) + + class DemurrageTokenSimulation: - def __init__(self, chain_spec, settings, redistribute=True, cap=0): + def __init__(self, chain_spec, settings, redistribute=True, cap=0, actors=1): + self.chain_spec = chain_spec self.accounts = [] self.keystore = DictKeystore() self.signer = EIP155Signer(self.keystore) self.eth_helper = create_tester_signer(self.keystore) self.eth_backend = self.eth_helper.backend + self.gas_oracle = OverrideGasOracle(limit=100000, price=1) self.rpc = TestRPCConnection(None, self.eth_helper, self.signer) for a in self.keystore.list(): self.accounts.append(add_0x(to_checksum_address(a))) @@ -36,3 +55,83 @@ class DemurrageTokenSimulation: if (r['status'] != 1): raise RuntimeError('contract deployment failed') self.address = r['contract_address'] + + self.period_seconds = settings.period_minutes * 60 + + o = block_latest() + r = self.rpc.do(o) + self.last_block = r + + o = block_by_number(r) + r = self.rpc.do(o) + self.last_timestamp = r['timestamp'] + + self.actors = [] + for i in range(actors): + idx = i % 10 + address = self.keystore.new() + self.actors.append(address) + self.accounts.append(address) + + nonce_oracle = RPCNonceOracle(self.accounts[idx], conn=self.rpc) + c = Gas(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=self.gas_oracle) + (tx_hash, o) = c.create(self.accounts[idx], address, 100000 * 1000000) + self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + if r['status'] != 1: + raise RuntimeError('failed gas transfer to account #{}: {} from {}'.format(i, address, self.accounts[idx])) + logg.debug('added actor account #{}: {}'.format(i, address)) + + self.eth_helper.disable_auto_mine_transactions() + + logg.info('intialized at block {} timestamp {} period {} demurrage level {} sink address {} (first address in keystore)'.format( + self.last_block, + self.last_timestamp, + settings.period_minutes, + settings.demurrage_level, + settings.sink_address, + ) + ) + + self.caller_contract = DemurrageToken(self.chain_spec) + + + def mint(self, recipient, value): + nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.rpc) + c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=self.gas_oracle) + (tx_hash, o) = c.mint_to(self.address, self.accounts[0], recipient, value) + self.rpc.do(o) + return tx_hash + + + def transfer(self, sender, recipient, value): + nonce_oracle = RPCNonceOracle(sender, conn=self.rpc) + c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=self.gas_oracle) + (tx_hash, o) = c.transfer(self.address, sender, recipient, value) + self.rpc.do(o) + return tx_hash + + + def balance(self, holder): + o = self.caller_contract.balance_of(self.address, holder, sender_address=self.accounts[0]) + r = self.rpc.do(o) + return self.caller_contract.parse_balance_of(r) + + + def next(self): + self.last_timestamp += self.period_seconds + self.eth_helper.mine_block() + self.eth_helper.time_travel(self.last_timestamp) + self.last_block += 1 + o = block_by_number(self.last_block) + r = self.rpc.do(o) + + for tx_hash in r['transactions']: + o = receipt(tx_hash) + rcpt = self.rpc.do(o) + if rcpt['status'] == 0: + raise RuntimeError('tx {} (block {} index {}) failed'.format(tx_hash, self.last_block, rcpt['transaction_index'])) + logg.debug('tx {} (block {} index {}) verified'.format(tx_hash, self.last_block, rcpt['transaction_index'])) + + return (self.last_block, self.last_timestamp) diff --git a/python/tests/sim/tests_sim.py b/python/tests/sim/tests_sim.py @@ -9,6 +9,7 @@ from chainlib.chain import ChainSpec from erc20_demurrage_token import DemurrageTokenSettings from erc20_demurrage_token.sim import DemurrageTokenSimulation +logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() @@ -16,18 +17,29 @@ class TestSim(unittest.TestCase): def setUp(self): self.chain_spec = ChainSpec('evm', 'foochain', 42) - self.cap = 1000000000 + #self.cap = 1000000000 + self.cap = 0 settings = DemurrageTokenSettings() settings.name = 'Simulated Demurrage Token' settings.symbol = 'SIM' settings.decimals = 6 settings.demurrage_level = 50 settings.period_minutes = 10800 - self.sim = DemurrageTokenSimulation(self.chain_spec, settings, redistribute=True, cap=self.cap) + self.sim = DemurrageTokenSimulation(self.chain_spec, settings, redistribute=True, cap=self.cap, actors=10) - def test_hello(self): - pass + def test_mint(self): + self.sim.mint(self.sim.actors[0], 1024) + self.sim.next() + balance = self.sim.balance(self.sim.actors[0]) + self.assertEqual(balance, 1024) + + + def test_transfer(self): + self.sim.mint(self.sim.actors[0], 1024) + self.sim.transfer(self.sim.actors[0], self.sim.actors[1], 500) + self.sim.next() + if __name__ == '__main__': unittest.main()