erc20-demurrage-token

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

commit 09b825808fe97b2f7da60641cbd55a86d406d401
parent 2717e29d91dd2b5f4a7efd14e28a44a11f14c66d
Author: lash <dev@holbrook.no>
Date:   Fri, 10 Feb 2023 13:45:29 +0000

Freeze accounts balances at expiry

Diffstat:
Apython/erc20_demurrage_token/expiry.py | 22++++++++++++++++++++++
Apython/erc20_demurrage_token/seal.py | 21+++++++++++++++++++++
Apython/tests/test_expiry.py | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 132 insertions(+), 0 deletions(-)

diff --git a/python/erc20_demurrage_token/expiry.py b/python/erc20_demurrage_token/expiry.py @@ -0,0 +1,22 @@ +# external imports +from chainlib.eth.tx import ( + TxFactory, + TxFormat, + ) +from chainlib.eth.contract import ( + ABIContractEncoder, + ABIContractType, + ) + +class ExpiryContract(TxFactory): + + def set_expires(self, contract_address, sender_address, expire_timestamp, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('setExpires') + enc.typ(ABIContractType.UINT256) + enc.uint256(expire_timestamp) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx diff --git a/python/erc20_demurrage_token/seal.py b/python/erc20_demurrage_token/seal.py @@ -0,0 +1,21 @@ +# external imports +from chainlib.eth.tx import ( + TxFactory, + TxFormat, + ) +from chainlib.eth.contract import ( + ABIContractEncoder, + ) + +class SealedContract(TxFactory): + + def set_state(self, contract_address, sender_address, seal, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('seal') + enc.typ(ABIContractType.UINT256) + enc.uint256(seal) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx diff --git a/python/tests/test_expiry.py b/python/tests/test_expiry.py @@ -0,0 +1,89 @@ +# 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 erc20_demurrage_token.unittest import TestDemurrageDefault + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +testdir = os.path.dirname(__file__) + + +class TestExpire(TestDemurrageDefault): + + def test_expires(self): + mint_amount = self.default_supply + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + for i in range(3): + (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[i+1], mint_amount) + r = self.rpc.do(o) + + targetish_time = self.start_time + (self.period_seconds * 2) + (tx_hash, o) = c.set_expires(self.address, self.accounts[0], targetish_time) + r = self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + self.backend.time_travel(targetish_time + 60) + o = block_latest() + r = self.rpc.do(o) + o = block_by_number(r) + r = self.rpc.do(o) + self.assertGreaterEqual(r['timestamp'], targetish_time) + + nonce_oracle = RPCNonceOracle(self.sink_address, self.rpc) + c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash, o) = c.transfer(self.address, self.sink_address, self.accounts[2], 1) + r = self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0]) + r = self.rpc.do(o) + balance = c.parse_balance(r) + self.assert_within(balance, 0.9604 * mint_amount, 1) + + o = c.total_supply(self.address, sender_address=self.accounts[0]) + r = self.rpc.do(o) + supply = c.parse_balance(r) + + (tx_hash, o) = c.change_period(self.address, self.sink_address) + r = self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0]) + r = self.rpc.do(o) + balance = c.parse_balance(r) + + o = c.decay_by(self.address, supply, int((targetish_time - self.start_time) / 60), sender_address=self.sink_address) + r = self.rpc.do(o) + target_balance = c.parse_balance(r) + + self.assert_within_lower(balance, supply - target_balance, 0.0001) + + +if __name__ == '__main__': + unittest.main()