mirror of
git://holbrook.no/erc20-demurrage-token
synced 2026-05-15 09:07:19 +02:00
Bump eth-erc20. add initial single and cap contract adaptations
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -40,13 +40,13 @@ class DemurrageTokenSettings:
|
||||
|
||||
class DemurrageToken(ERC20):
|
||||
|
||||
__abi = None
|
||||
__bytecode = None
|
||||
__abi = {}
|
||||
__bytecode = {}
|
||||
|
||||
def constructor(self, sender_address, settings, redistribute=True, cap=0, tx_format=TxFormat.JSONRPC):
|
||||
if not redistribute or cap:
|
||||
raise NotImplementedError('token cap and sink only redistribution not yet implemented')
|
||||
code = DemurrageToken.bytecode()
|
||||
if int(cap) < 0:
|
||||
raise ValueError('cap must be 0 or positive integer')
|
||||
code = DemurrageToken.bytecode(multi=redistribute, cap=cap>0)
|
||||
enc = ABIContractEncoder()
|
||||
enc.string(settings.name)
|
||||
enc.string(settings.symbol)
|
||||
@@ -64,22 +64,39 @@ class DemurrageToken(ERC20):
|
||||
def gas(code=None):
|
||||
return 3500000
|
||||
|
||||
|
||||
@staticmethod
|
||||
def abi():
|
||||
if DemurrageToken.__abi == None:
|
||||
f = open(os.path.join(data_dir, 'DemurrageTokenMultiNocap.json'), 'r')
|
||||
DemurrageToken.__abi = json.load(f)
|
||||
f.close()
|
||||
return DemurrageToken.__abi
|
||||
def __to_contract_name(multi, cap):
|
||||
name = 'DemurrageToken'
|
||||
if multi:
|
||||
name += 'Multi'
|
||||
else:
|
||||
name += 'Single'
|
||||
if cap:
|
||||
name += 'Cap'
|
||||
else:
|
||||
name += 'Nocap'
|
||||
return name
|
||||
|
||||
|
||||
@staticmethod
|
||||
def bytecode():
|
||||
if DemurrageToken.__bytecode == None:
|
||||
f = open(os.path.join(data_dir, 'DemurrageTokenMultiNocap.bin'), 'r')
|
||||
DemurrageToken.__bytecode = f.read()
|
||||
def abi(multi=True, cap=False):
|
||||
name = DemurrageToken.__to_contract_name(multi, cap)
|
||||
if DemurrageToken.__abi.get(name) == None:
|
||||
f = open(os.path.join(data_dir, name + '.json'), 'r')
|
||||
DemurrageToken.__abi[name] = json.load(f)
|
||||
f.close()
|
||||
return DemurrageToken.__bytecode
|
||||
return DemurrageToken.__abi[name]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def bytecode(multi=True, cap=False):
|
||||
name = DemurrageToken.__to_contract_name(multi, cap)
|
||||
if DemurrageToken.__bytecode.get(name) == None:
|
||||
f = open(os.path.join(data_dir, name + '.bin'), 'r')
|
||||
DemurrageToken.__bytecode[name] = f.read()
|
||||
f.close()
|
||||
return DemurrageToken.__bytecode[name]
|
||||
|
||||
|
||||
def add_minter(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
chainlib~=0.0.3rc3
|
||||
eth-erc20~=0.0.9a3
|
||||
eth-erc20~=0.0.9a4
|
||||
crypto-dev-signer~=0.4.14b3
|
||||
|
||||
@@ -35,6 +35,10 @@ class TestDemurrage(EthTesterCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDemurrage, self).setUp()
|
||||
|
||||
self.tax_level = TAX_LEVEL
|
||||
self.period = PERIOD
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
self.settings = DemurrageTokenSettings()
|
||||
self.settings.name = 'Foo Token'
|
||||
@@ -64,16 +68,31 @@ class TestDemurrage(EthTesterCase):
|
||||
|
||||
class TestDemurrageDefault(TestDemurrage):
|
||||
|
||||
def __deploy(self, interface):
|
||||
self.default_supply = 1000000000000
|
||||
self.supply_cap = self.default_supply * 10
|
||||
|
||||
(tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=True, cap=0)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
self.addresses['MultiNocap'] = r['contract_address']
|
||||
|
||||
(tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=0)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
self.addresses['SingleNocap'] = r['contract_address']
|
||||
|
||||
|
||||
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)
|
||||
(tx_hash, o) = c.constructor(self.accounts[0], self.settings)
|
||||
r = self.rpc.do(o)
|
||||
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
self.address = r['contract_address']
|
||||
self.addresses = {}
|
||||
self.__deploy(c)
|
||||
self.address = self.addresses['MultiNocap']
|
||||
|
||||
@@ -26,11 +26,6 @@ logg = logging.getLogger()
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
#BLOCKTIME = 5 # seconds
|
||||
TAX_LEVEL = 10000 * 2 # 2%
|
||||
#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month
|
||||
PERIOD = 1
|
||||
|
||||
|
||||
class TestRedistribution(TestDemurrageDefault):
|
||||
|
||||
@@ -104,7 +99,7 @@ class TestRedistribution(TestDemurrageDefault):
|
||||
|
||||
|
||||
def test_redistribution_balance_on_zero_participants(self):
|
||||
supply = 1000000000000
|
||||
supply = self.default_supply
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
@@ -127,7 +122,7 @@ class TestRedistribution(TestDemurrageDefault):
|
||||
o = c.total_supply(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
total_supply = c.parse_total_supply(r)
|
||||
sink_increment = int(total_supply * (TAX_LEVEL / 1000000))
|
||||
sink_increment = int(total_supply * (self.tax_level / 1000000))
|
||||
self.assertEqual(supply, total_supply)
|
||||
|
||||
for l in rcpt['logs']:
|
||||
@@ -136,14 +131,14 @@ class TestRedistribution(TestDemurrageDefault):
|
||||
self.assertEqual(period, 2)
|
||||
b = bytes.fromhex(strip_0x(l['data']))
|
||||
remainder = int.from_bytes(b, 'big')
|
||||
self.assertEqual(remainder, int((1000000 - TAX_LEVEL) * (10 ** 32)))
|
||||
self.assertEqual(remainder, int((1000000 - self.tax_level) * (10 ** 32)))
|
||||
|
||||
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
sink_balance = c.parse_balance_of(r)
|
||||
|
||||
self.assertEqual(sink_balance, int(sink_increment * 0.98))
|
||||
self.assertEqual(sink_balance, int(sink_increment * (1000000 - TAX_LEVEL) / 1000000))
|
||||
self.assertEqual(sink_balance, int(sink_increment * (1000000 - self.tax_level) / 1000000))
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
@@ -215,14 +210,14 @@ class TestRedistribution(TestDemurrageDefault):
|
||||
r = self.rpc.do(o)
|
||||
bummer_balance = c.parse_balance_of(r)
|
||||
|
||||
self.assertEqual(bummer_balance, mint_amount - (mint_amount * (TAX_LEVEL / 1000000)))
|
||||
self.assertEqual(bummer_balance, mint_amount - (mint_amount * (self.tax_level / 1000000)))
|
||||
logg.debug('bal {} '.format(bummer_balance))
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
bummer_balance = c.parse_balance_of(r)
|
||||
spender_balance = mint_amount - spend_amount
|
||||
spender_decayed_balance = int(spender_balance - (spender_balance * (TAX_LEVEL / 1000000)))
|
||||
spender_decayed_balance = int(spender_balance - (spender_balance * (self.tax_level / 1000000)))
|
||||
self.assertEqual(bummer_balance, spender_decayed_balance)
|
||||
logg.debug('bal {} '.format(bummer_balance))
|
||||
|
||||
@@ -254,9 +249,9 @@ class TestRedistribution(TestDemurrageDefault):
|
||||
actual_period = c.parse_actual_period(r)
|
||||
logg.debug('period {}'.format(actual_period))
|
||||
|
||||
redistribution = int((z / 2) * (TAX_LEVEL / 1000000))
|
||||
redistribution = int((z / 2) * (self.tax_level / 1000000))
|
||||
spender_new_base_balance = ((mint_amount - spend_amount) + redistribution)
|
||||
spender_new_decayed_balance = int(spender_new_base_balance - (spender_new_base_balance * (TAX_LEVEL / 1000000)))
|
||||
spender_new_decayed_balance = int(spender_new_base_balance - (spender_new_base_balance * (self.tax_level / 1000000)))
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
|
||||
61
python/tests/test_single.py
Normal file
61
python/tests/test_single.py
Normal file
@@ -0,0 +1,61 @@
|
||||
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
|
||||
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 TestDemurrageDefault
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class TestRedistributionSingle(TestDemurrageDefault):
|
||||
|
||||
def test_single_even_if_multiple(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
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], 100000000)
|
||||
r = self.rpc.do(o)
|
||||
|
||||
external_address = to_checksum_address('0x' + os.urandom(20).hex())
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.transfer(self.address, self.accounts[1], external_address, 10000000)
|
||||
r = self.rpc.do(o)
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[3], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.transfer(self.address, self.accounts[2], external_address, 20000000)
|
||||
r = self.rpc.do(o)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, self.accounts[0])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
rcpt = self.rpc.do(o)
|
||||
self.assertEqual(rcpt['status'], 1)
|
||||
|
||||
(tx_hash, o) = c.change_period(self.address, self.accounts[0])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
Reference in New Issue
Block a user