Compare commits
12 Commits
lash/tests
...
lash/clean
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a168d81f9 | ||
|
|
2f57da0e8e
|
||
|
|
51c9c94261
|
||
|
|
e332f76a04
|
||
|
|
ebef1948aa
|
||
|
|
22cd7cf18c
|
||
|
|
7a9572e978
|
||
|
|
8f11bdc2cc
|
||
|
|
aab0bc243c
|
||
|
|
364731b220
|
||
|
|
a8ff826dad
|
||
|
|
3ae75075e4
|
@@ -1,4 +0,0 @@
|
||||
from .token import (
|
||||
DemurrageToken,
|
||||
DemurrageTokenSettings,
|
||||
)
|
||||
@@ -1,278 +0,0 @@
|
||||
# standard imports
|
||||
import os
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
from chainlib.eth.tx import (
|
||||
TxFactory,
|
||||
TxFormat,
|
||||
)
|
||||
from chainlib.hash import keccak256_string_to_hex
|
||||
from chainlib.eth.contract import (
|
||||
ABIContractEncoder,
|
||||
ABIContractType,
|
||||
abi_decode_single,
|
||||
)
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
from chainlib.jsonrpc import jsonrpc_template
|
||||
from eth_erc20 import ERC20
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token.data import data_dir
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DemurrageTokenSettings:
|
||||
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
self.symbol = None
|
||||
self.decimals = None
|
||||
self.demurrage_level = None
|
||||
self.period_minutes = None
|
||||
self.sink_address = None
|
||||
|
||||
|
||||
class DemurrageToken(ERC20):
|
||||
|
||||
__abi = None
|
||||
__bytecode = None
|
||||
|
||||
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()
|
||||
enc = ABIContractEncoder()
|
||||
enc.string(settings.name)
|
||||
enc.string(settings.symbol)
|
||||
enc.uint256(settings.decimals)
|
||||
enc.uint256(settings.demurrage_level)
|
||||
enc.uint256(settings.period_minutes)
|
||||
enc.address(settings.sink_address)
|
||||
code += enc.get()
|
||||
tx = self.template(sender_address, None, use_nonce=True)
|
||||
tx = self.set_code(tx, code)
|
||||
return self.finalize(tx, tx_format)
|
||||
|
||||
|
||||
@staticmethod
|
||||
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
|
||||
|
||||
|
||||
@staticmethod
|
||||
def bytecode():
|
||||
if DemurrageToken.__bytecode == None:
|
||||
f = open(os.path.join(data_dir, 'DemurrageTokenMultiNocap.bin'), 'r')
|
||||
DemurrageToken.__bytecode = f.read()
|
||||
f.close()
|
||||
return DemurrageToken.__bytecode
|
||||
|
||||
|
||||
def add_minter(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('addMinter')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(address)
|
||||
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
|
||||
|
||||
|
||||
def remove_minter(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('removeMinter')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(address)
|
||||
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
|
||||
|
||||
|
||||
def mint_to(self, contract_address, sender_address, address, value, tx_format=TxFormat.JSONRPC):
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('mintTo')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.address(address)
|
||||
enc.uint256(value)
|
||||
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
|
||||
|
||||
|
||||
def to_base_amount(self, contract_address, value, sender_address=ZERO_ADDRESS):
|
||||
o = jsonrpc_template()
|
||||
o['method'] = 'eth_call'
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('toBaseAmount')
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.uint256(value)
|
||||
data = add_0x(enc.get())
|
||||
tx = self.template(sender_address, contract_address)
|
||||
tx = self.set_code(tx, data)
|
||||
o['params'].append(self.normalize(tx))
|
||||
o['params'].append('latest')
|
||||
return o
|
||||
|
||||
|
||||
def remainder(self, contract_address, parts, whole, sender_address=ZERO_ADDRESS):
|
||||
o = jsonrpc_template()
|
||||
o['method'] = 'eth_call'
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('remainder')
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.uint256(parts)
|
||||
enc.uint256(whole)
|
||||
data = add_0x(enc.get())
|
||||
tx = self.template(sender_address, contract_address)
|
||||
tx = self.set_code(tx, data)
|
||||
o['params'].append(self.normalize(tx))
|
||||
o['params'].append('latest')
|
||||
return o
|
||||
|
||||
|
||||
def redistributions(self, contract_address, idx, sender_address=ZERO_ADDRESS):
|
||||
o = jsonrpc_template()
|
||||
o['method'] = 'eth_call'
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('redistributions')
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.uint256(idx)
|
||||
data = add_0x(enc.get())
|
||||
tx = self.template(sender_address, contract_address)
|
||||
tx = self.set_code(tx, data)
|
||||
o['params'].append(self.normalize(tx))
|
||||
o['params'].append('latest')
|
||||
return o
|
||||
|
||||
|
||||
def account_period(self, contract_address, address, sender_address=ZERO_ADDRESS):
|
||||
o = jsonrpc_template()
|
||||
o['method'] = 'eth_call'
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('accountPeriod')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(address)
|
||||
data = add_0x(enc.get())
|
||||
tx = self.template(sender_address, contract_address)
|
||||
tx = self.set_code(tx, data)
|
||||
o['params'].append(self.normalize(tx))
|
||||
o['params'].append('latest')
|
||||
return o
|
||||
|
||||
|
||||
def to_redistribution_period(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
|
||||
o = jsonrpc_template()
|
||||
o['method'] = 'eth_call'
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('toRedistributionPeriod')
|
||||
enc.typ(ABIContractType.BYTES32)
|
||||
enc.bytes32(redistribution)
|
||||
data = add_0x(enc.get())
|
||||
tx = self.template(sender_address, contract_address)
|
||||
tx = self.set_code(tx, data)
|
||||
o['params'].append(self.normalize(tx))
|
||||
o['params'].append('latest')
|
||||
return o
|
||||
|
||||
|
||||
def apply_demurrage(self, contract_address, sender_address):
|
||||
return self.transact_noarg('applyDemurrage', contract_address, sender_address)
|
||||
|
||||
|
||||
def change_period(self, contract_address, sender_address):
|
||||
return self.transact_noarg('changePeriod', contract_address, sender_address)
|
||||
|
||||
|
||||
def apply_redistribution_on_account(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('applyRedistributionOnAccount')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(address)
|
||||
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
|
||||
|
||||
|
||||
def actual_period(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||
return self.call_noarg('actualPeriod', contract_address, sender_address=sender_address)
|
||||
|
||||
|
||||
def period_start(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||
return self.call_noarg('periodStart', contract_address, sender_address=sender_address)
|
||||
|
||||
|
||||
def period_duration(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||
return self.call_noarg('periodDuration', contract_address, sender_address=sender_address)
|
||||
|
||||
|
||||
def demurrage_amount(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||
return self.call_noarg('demurrageAmount', contract_address, sender_address=sender_address)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_actual_period(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_period_start(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_period_duration(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_demurrage_amount(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_remainder(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_to_base_amount(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_redistributions(self, v):
|
||||
return abi_decode_single(ABIContractType.BYTES32, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_account_period(self, v):
|
||||
return abi_decode_single(ABIContractType.ADDRESS, v)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_to_redistribution_period(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
@@ -1,3 +1,3 @@
|
||||
chainlib~=0.0.3rc3
|
||||
eth-erc20~=0.0.9a3
|
||||
chainlib~=0.0.3a1
|
||||
eth-erc20~=0.0.9a1
|
||||
crypto-dev-signer~=0.4.14b3
|
||||
|
||||
1
python/sarafu_token/__init__.py
Normal file
1
python/sarafu_token/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .token import RedistributedDemurrageToken
|
||||
File diff suppressed because one or more lines are too long
@@ -29,7 +29,7 @@ from chainlib.eth.tx import receipt
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token import DemurrageToken
|
||||
from sarafu_token import RedistributedDemurrageToken
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
@@ -92,9 +92,9 @@ else:
|
||||
|
||||
gas_oracle = None
|
||||
if args.gas_price !=None:
|
||||
gas_oracle = OverrideGasOracle(price=args.gas_price, conn=rpc, code_callback=DemurrageToken.gas)
|
||||
gas_oracle = OverrideGasOracle(price=args.gas_price, conn=rpc, code_callback=RedistributedDemurrageToken.gas)
|
||||
else:
|
||||
gas_oracle = RPCGasOracle(rpc, code_callback=DemurrageToken.gas)
|
||||
gas_oracle = RPCGasOracle(rpc, code_callback=RedistributedDemurrageToken.gas)
|
||||
|
||||
dummy = args.d
|
||||
|
||||
@@ -103,7 +103,7 @@ if token_name == None:
|
||||
token_name = args.symbol
|
||||
|
||||
def main():
|
||||
c = DemurrageToken(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
|
||||
c = RedistributedDemurrageToken(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
|
||||
(tx_hash_hex, o) = c.constructor(
|
||||
signer_address,
|
||||
token_name,
|
||||
133
python/sarafu_token/runnable/legacy/deploy.py
Normal file
133
python/sarafu_token/runnable/legacy/deploy.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""Deploys Sarafu token
|
||||
|
||||
.. moduleauthor:: Louis Holbrook <dev@holbrook.no>
|
||||
.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
|
||||
|
||||
"""
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# standard imports
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import logging
|
||||
import time
|
||||
from enum import Enum
|
||||
|
||||
# third-party imports
|
||||
import web3
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
from crypto_dev_signer.keystore import DictKeystore
|
||||
from crypto_dev_signer.eth.helper import EthTxExecutor
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
logging.getLogger('web3').setLevel(logging.WARNING)
|
||||
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
||||
|
||||
script_dir = os.path.dirname(__file__)
|
||||
data_dir = os.path.join(script_dir, '..', '..', 'data')
|
||||
|
||||
|
||||
argparser = argparse.ArgumentParser()
|
||||
argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='Web3 provider url (http only)')
|
||||
argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed')
|
||||
argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed')
|
||||
argparser.add_argument('-e', action='store_true', help='Treat all transactions as essential')
|
||||
argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='Ethereum:1', help='Chain specification string')
|
||||
argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing')
|
||||
argparser.add_argument('--name', dest='n', default='Giftable Token', type=str, help='Token name')
|
||||
argparser.add_argument('--symbol', dest='s', default='GFT', type=str, help='Token symbol')
|
||||
argparser.add_argument('--decimals', dest='d', default=18, type=int, help='Token decimals')
|
||||
argparser.add_argument('--minter', action='append', type=str, help='Minter to add')
|
||||
argparser.add_argument('--sink-address', type=str, help='Sink address (if not set, signer address is used)')
|
||||
argparser.add_argument('--abi-dir', dest='abi_dir', type=str, default=data_dir, help='Directory containing bytecode and abi (default: {})'.format(data_dir))
|
||||
|
||||
argparser.add_argument('-v', action='store_true', help='Be verbose')
|
||||
argparser.add_argument('taxlevel_minute', type=int, help='Tax level per minute in ppm')
|
||||
argparser.add_argument('period_minutes', type=int, help='Redistribution period, in minutes')
|
||||
args = argparser.parse_args()
|
||||
|
||||
if args.v:
|
||||
logg.setLevel(logging.DEBUG)
|
||||
|
||||
block_last = args.w
|
||||
block_all = args.ww
|
||||
|
||||
w3 = web3.Web3(web3.Web3.HTTPProvider(args.p))
|
||||
|
||||
signer_address = None
|
||||
keystore = DictKeystore()
|
||||
if args.y != None:
|
||||
logg.debug('loading keystore file {}'.format(args.y))
|
||||
signer_address = keystore.import_keystore_file(args.y)
|
||||
logg.debug('now have key for signer address {}'.format(signer_address))
|
||||
signer = EIP155Signer(keystore)
|
||||
|
||||
chain_pair = args.i.split(':')
|
||||
chain_id = int(chain_pair[1])
|
||||
|
||||
helper = EthTxExecutor(
|
||||
w3,
|
||||
signer_address,
|
||||
signer,
|
||||
chain_id,
|
||||
block=args.ww,
|
||||
)
|
||||
#g = ERC20TxFactory(signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle, chain_id=chain_id)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
f = open(os.path.join(args.abi_dir, 'RedistributedDemurrageToken.json'), 'r')
|
||||
abi = json.load(f)
|
||||
f.close()
|
||||
|
||||
f = open(os.path.join(args.abi_dir, 'RedistributedDemurrageToken.bin'), 'r')
|
||||
bytecode = f.read()
|
||||
f.close()
|
||||
|
||||
sink_address = args.sink_address
|
||||
if sink_address == None:
|
||||
sink_address = signer_address
|
||||
|
||||
c = w3.eth.contract(abi=abi, bytecode=bytecode)
|
||||
(tx_hash, rcpt) = helper.sign_and_send(
|
||||
[
|
||||
c.constructor(args.n, args.s, args.d, args.taxlevel_minute, args.period_minutes, sink_address).buildTransaction
|
||||
],
|
||||
force_wait=True,
|
||||
)
|
||||
logg.debug('tx hash {} rcpt {}'.format(tx_hash, rcpt))
|
||||
|
||||
address = rcpt.contractAddress
|
||||
logg.debug('token contract mined {} {} {} {}'.format(address, args.n, args.s, args.d, args.taxlevel_minute, args.period_minutes, sink_address))
|
||||
c = w3.eth.contract(abi=abi, address=address)
|
||||
|
||||
balance = c.functions.balanceOf(signer_address).call()
|
||||
logg.info('balance {}: {} {}'.format(signer_address, balance, tx_hash))
|
||||
|
||||
if args.minter != None:
|
||||
for a in args.minter:
|
||||
if a == signer_address:
|
||||
continue
|
||||
(tx_hash, rcpt) = helper.sign_and_send(
|
||||
[
|
||||
c.functions.addMinter(a).buildTransaction,
|
||||
],
|
||||
)
|
||||
logg.debug('minter add {} {}'.format(a, tx_hash))
|
||||
|
||||
if block_last:
|
||||
helper.wait_for()
|
||||
|
||||
print(address)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
87
python/sarafu_token/token.py
Normal file
87
python/sarafu_token/token.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# standard imports
|
||||
import os
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
from chainlib.eth.tx import (
|
||||
TxFactory,
|
||||
TxFormat,
|
||||
)
|
||||
from chainlib.hash import keccak256_string_to_hex
|
||||
from chainlib.eth.contract import (
|
||||
ABIContractEncoder,
|
||||
ABIContractType,
|
||||
)
|
||||
|
||||
# local imports
|
||||
from sarafu_token.data import data_dir
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RedistributedDemurrageToken(TxFactory):
|
||||
|
||||
__abi = None
|
||||
__bytecode = None
|
||||
|
||||
def constructor(self, sender_address, name, symbol, decimals, demurrage_level, period_minutes, sink_address, tx_format=TxFormat.JSONRPC):
|
||||
code = RedistributedDemurrageToken.bytecode()
|
||||
enc = ABIContractEncoder()
|
||||
enc.string(name)
|
||||
enc.string(symbol)
|
||||
enc.uint256(decimals)
|
||||
enc.uint256(demurrage_level)
|
||||
enc.uint256(period_minutes)
|
||||
enc.address(sink_address)
|
||||
code += enc.get()
|
||||
tx = self.template(sender_address, None, use_nonce=True)
|
||||
tx = self.set_code(tx, code)
|
||||
return self.finalize(tx, tx_format)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def gas(code=None):
|
||||
return 3500000
|
||||
|
||||
@staticmethod
|
||||
def abi():
|
||||
if RedistributedDemurrageToken.__abi == None:
|
||||
f = open(os.path.join(data_dir, 'RedistributedDemurrageToken.json'), 'r')
|
||||
RedistributedDemurrageToken.__abi = json.load(f)
|
||||
f.close()
|
||||
return RedistributedDemurrageToken.__abi
|
||||
|
||||
|
||||
@staticmethod
|
||||
def bytecode():
|
||||
if RedistributedDemurrageToken.__bytecode == None:
|
||||
f = open(os.path.join(data_dir, 'RedistributedDemurrageToken.bin'), 'r')
|
||||
RedistributedDemurrageToken.__bytecode = f.read()
|
||||
f.close()
|
||||
return RedistributedDemurrageToken.__bytecode
|
||||
|
||||
|
||||
def add_minter(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('addMinter')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(address)
|
||||
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
|
||||
|
||||
|
||||
def mint_to(self, contract_address, sender_address, address, value, tx_format=TxFormat.JSONRPC):
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('mintTo')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.address(address)
|
||||
enc.uint256(value)
|
||||
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
|
||||
@@ -1,15 +1,12 @@
|
||||
[metadata]
|
||||
name = erc20-demurrage-token
|
||||
version = 0.0.1b1
|
||||
name = sarafu-token
|
||||
version = 0.0.1a8
|
||||
description = ERC20 token with redistributed continual demurrage
|
||||
author = Louis Holbrook
|
||||
author_email = dev@holbrook.no
|
||||
url = https://gitlab.com/grassrootseconomics/sarafu-token
|
||||
keywords =
|
||||
ethereum
|
||||
blockchain
|
||||
cryptocurrency
|
||||
erc20
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
Operating System :: OS Independent
|
||||
@@ -27,14 +24,18 @@ licence_files =
|
||||
include_package_data = True
|
||||
python_requires = >= 3.6
|
||||
packages =
|
||||
erc20_demurrage_token
|
||||
erc20_demurrage_token.runnable
|
||||
sarafu_token
|
||||
sarafu_token.runnable
|
||||
install_requires =
|
||||
chainlib~=0.0.3a1
|
||||
crypto-dev-signer~=0.4.14b3
|
||||
|
||||
|
||||
[options.package_data]
|
||||
* =
|
||||
data/DemurrageToken*.bin
|
||||
data/DemurrageToken*.json
|
||||
data/RedistributedDemurrageToken.bin
|
||||
data/RedistributedDemurrageToken.json
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
erc20-demurrage-token-deploy = erc20_demurrage_token.runnable.deploy:main
|
||||
sarafu-token-deploy = sarafu_token.runnable.deploy:main
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#web3==5.12.2
|
||||
web3==5.12.2
|
||||
eth_tester==0.5.0b3
|
||||
py-evm==0.3.0a20
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# 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 = 1
|
||||
|
||||
|
||||
|
||||
class TestDemurrage(EthTesterCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDemurrage, self).setUp()
|
||||
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)
|
||||
logg.debug('r {}'.format(r))
|
||||
try:
|
||||
self.start_time = int(r['timestamp'], 16)
|
||||
except TypeError:
|
||||
self.start_time = int(r['timestamp'])
|
||||
|
||||
|
||||
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)
|
||||
(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']
|
||||
@@ -5,238 +5,206 @@ 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
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token import DemurrageToken
|
||||
|
||||
# test imports
|
||||
from tests.base import TestDemurrageDefault
|
||||
# third-party imports
|
||||
import web3
|
||||
import eth_tester
|
||||
import eth_abi
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
logging.getLogger('web3').setLevel(logging.WARNING)
|
||||
logging.getLogger('eth.vm').setLevel(logging.WARNING)
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
#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 = 1
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
contract = None
|
||||
|
||||
def setUp(self):
|
||||
eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({
|
||||
'gas_limit': 9000000,
|
||||
})
|
||||
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.bin'), 'r')
|
||||
self.bytecode = f.read()
|
||||
f.close()
|
||||
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.json'), 'r')
|
||||
self.abi = json.load(f)
|
||||
f.close()
|
||||
|
||||
|
||||
backend = eth_tester.PyEVMBackend(eth_params)
|
||||
self.eth_tester = eth_tester.EthereumTester(backend)
|
||||
provider = web3.Web3.EthereumTesterProvider(self.eth_tester)
|
||||
self.w3 = web3.Web3(provider)
|
||||
self.sink_address = self.w3.eth.accounts[9]
|
||||
|
||||
c = self.w3.eth.contract(abi=self.abi, bytecode=self.bytecode)
|
||||
tx_hash = c.constructor('Foo Token', 'FOO', 6, TAX_LEVEL * (10 ** 32), PERIOD, self.sink_address).transact({'from': self.w3.eth.accounts[0]})
|
||||
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.contract = self.w3.eth.contract(abi=self.abi, address=r.contractAddress)
|
||||
|
||||
self.start_block = self.w3.eth.blockNumber
|
||||
b = self.w3.eth.getBlock(self.start_block)
|
||||
self.start_time = b['timestamp']
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
class TestBasic(TestDemurrageDefault):
|
||||
|
||||
def test_hello(self):
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(self.contract.functions.actualPeriod().call(), 1)
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
self.assertEqual(self.contract.functions.actualPeriod().call(), 2)
|
||||
|
||||
|
||||
def test_apply_demurrage(self):
|
||||
modifier = 10 * (10 ** 37)
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
#demurrage_modifier = self.contract.functions.demurrageModifier().call()
|
||||
#demurrage_modifier &= (1 << 128) - 1
|
||||
demurrage_amount = self.contract.functions.demurrageAmount().call()
|
||||
#self.assertEqual(modifier, demurrage_modifier)
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
|
||||
self.backend.time_travel(self.start_time + 59)
|
||||
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
self.eth_tester.time_travel(self.start_time + 59)
|
||||
#demurrage_modifier = self.contract.functions.demurrageModifier().call()
|
||||
demurrage_amount = self.contract.functions.demurrageAmount().call()
|
||||
#demurrage_modifier &= (1 << 128) - 1
|
||||
#self.assertEqual(modifier, demurrage_modifier)
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
modifier = int(98 * (10 ** 36))
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
tx_hash = self.contract.functions.applyDemurrage().transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
|
||||
#demurrage_modifier = self.contract.functions.demurrageModifier().call()
|
||||
demurrage_amount = self.contract.functions.demurrageAmount().call()
|
||||
#demurrage_modifier &= (1 << 128) - 1
|
||||
#self.assertEqual(int(98 * (10 ** 36)), demurrage_modifier)
|
||||
self.assertEqual(int(98 * (10 ** 36)), demurrage_amount)
|
||||
|
||||
|
||||
def test_mint(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], 1024)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1024).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
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_of(r)
|
||||
balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance, 1024)
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 976)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 976).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
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_of(r)
|
||||
balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance, 2000)
|
||||
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
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.eth_tester.time_travel(self.start_time + 61)
|
||||
balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance, int(2000 * 0.98))
|
||||
|
||||
|
||||
def test_minter_control(self):
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[2], 1024).transact({'from': self.w3.eth.accounts[1]})
|
||||
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
tx_hash = self.contract.functions.addMinter(self.w3.eth.accounts[1]).transact({'from': self.w3.eth.accounts[1]})
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
tx_hash = self.contract.functions.addMinter(self.w3.eth.accounts[1]).transact({'from': self.w3.eth.accounts[0]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 0)
|
||||
|
||||
(tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[1])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 0)
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
tx_hash = self.contract.functions.addMinter(self.w3.eth.accounts[2]).transact({'from': self.w3.eth.accounts[1]})
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[1])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[2], 1024).transact({'from': self.w3.eth.accounts[1]})
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
tx_hash = self.contract.functions.addMinter(self.w3.eth.accounts[1]).transact({'from': self.w3.eth.accounts[2]})
|
||||
|
||||
(tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[2])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 0)
|
||||
tx_hash = self.contract.functions.removeMinter(self.w3.eth.accounts[1]).transact({'from': self.w3.eth.accounts[1]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
(tx_hash, o) = c.remove_minter(self.address, self.accounts[1], self.accounts[1])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[2], 1024).transact({'from': self.w3.eth.accounts[1]})
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 0)
|
||||
|
||||
|
||||
def test_base_amount(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1000).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||
self.rpc.do(o)
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = c.to_base_amount(self.address, 1000, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
amount = c.parse_to_base_amount(r)
|
||||
self.assertEqual(amount, 1020)
|
||||
self.contract.functions.applyDemurrage().transact()
|
||||
#demurrage_modifier = self.contract.functions.demurrageModifier().call()
|
||||
#demurrage_amount = self.contract.functions.toDemurrageAmount(demurrage_modifier).call()
|
||||
demurrage_amount = self.contract.functions.demurrageAmount().call()
|
||||
|
||||
a = self.contract.functions.toBaseAmount(1000).call();
|
||||
self.assertEqual(a, 1020)
|
||||
|
||||
|
||||
def test_transfer(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1024).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||
self.rpc.do(o)
|
||||
tx_hash = self.contract.functions.transfer(self.w3.eth.accounts[2], 500).transact({'from': self.w3.eth.accounts[1]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
logg.debug('tx {}'.format(r))
|
||||
|
||||
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[2], 500)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance_alice, 524)
|
||||
|
||||
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, 524)
|
||||
balance_bob = self.contract.functions.balanceOf(self.w3.eth.accounts[2]).call()
|
||||
self.assertEqual(balance_bob, 500)
|
||||
|
||||
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, 500)
|
||||
tx_hash = self.contract.functions.transfer(self.w3.eth.accounts[2], 500).transact({'from': self.w3.eth.accounts[1]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
logg.debug('tx {}'.format(r))
|
||||
|
||||
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[2], self.accounts[1], 500)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
|
||||
|
||||
def test_transfer_from(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], 1024)
|
||||
self.rpc.do(o)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1024).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.approve(self.address, self.accounts[1], self.accounts[2], 500)
|
||||
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_of(r)
|
||||
self.assertEqual(balance, 1024)
|
||||
tx_hash = self.contract.functions.approve(self.w3.eth.accounts[2], 500).transact({'from': self.w3.eth.accounts[1]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
logg.debug('tx {}'.format(r))
|
||||
|
||||
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_from(self.address, self.accounts[2], self.accounts[1], self.accounts[3], 500)
|
||||
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_of(r)
|
||||
self.assertEqual(balance, 524)
|
||||
balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance_alice, 1024)
|
||||
|
||||
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, 500)
|
||||
tx_hash = self.contract.functions.transferFrom(self.w3.eth.accounts[1], self.w3.eth.accounts[3], 500).transact({'from': self.w3.eth.accounts[2]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
logg.debug('tx {}'.format(r))
|
||||
|
||||
balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance_alice, 524)
|
||||
|
||||
balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[3]).call()
|
||||
self.assertEqual(balance_alice, 500)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -4,64 +4,76 @@ 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
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token import DemurrageToken
|
||||
|
||||
# test imports
|
||||
from tests.base import TestDemurrageDefault
|
||||
# third-party imports
|
||||
import web3
|
||||
import eth_tester
|
||||
import eth_abi
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
logging.getLogger('web3').setLevel(logging.WARNING)
|
||||
logging.getLogger('eth.vm').setLevel(logging.WARNING)
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
class TestPeriod(TestDemurrageDefault):
|
||||
#BLOCKTIME = 5 # seconds
|
||||
TAX_LEVEL = 10000 * 2 # 2%
|
||||
#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month
|
||||
PERIOD = 1
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
contract = None
|
||||
|
||||
def setUp(self):
|
||||
eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({
|
||||
'gas_limit': 9000000,
|
||||
})
|
||||
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.bin'), 'r')
|
||||
self.bytecode = f.read()
|
||||
f.close()
|
||||
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.json'), 'r')
|
||||
self.abi = json.load(f)
|
||||
f.close()
|
||||
|
||||
backend = eth_tester.PyEVMBackend(eth_params)
|
||||
self.eth_tester = eth_tester.EthereumTester(backend)
|
||||
provider = web3.Web3.EthereumTesterProvider(self.eth_tester)
|
||||
self.w3 = web3.Web3(provider)
|
||||
self.sink_address = self.w3.eth.accounts[9]
|
||||
|
||||
c = self.w3.eth.contract(abi=self.abi, bytecode=self.bytecode)
|
||||
tx_hash = c.constructor('Foo Token', 'FOO', 6, TAX_LEVEL * (10 ** 32), PERIOD, self.sink_address).transact({'from': self.w3.eth.accounts[0]})
|
||||
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.contract = self.w3.eth.contract(abi=self.abi, address=r.contractAddress)
|
||||
|
||||
self.start_block = self.w3.eth.blockNumber
|
||||
b = self.w3.eth.getBlock(self.start_block)
|
||||
self.start_time = b['timestamp']
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_period(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], 1024)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1024).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
tx_hash = self.contract.functions.changePeriod().transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.change_period(self.address, self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
o = c.redistributions(self.address, 1, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
redistribution = c.parse_redistributions(r)
|
||||
|
||||
o = c.to_redistribution_period(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
period = c.parse_to_redistribution_period(r)
|
||||
self.assertEqual(2, period)
|
||||
|
||||
o = c.redistributions(self.address, 1, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
redistribution = c.parse_redistributions(r)
|
||||
|
||||
o = c.to_redistribution_period(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
period = c.parse_to_redistribution_period(r)
|
||||
self.assertEqual(2, period)
|
||||
|
||||
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
period = c.parse_actual_period(r)
|
||||
self.assertEqual(2, period)
|
||||
redistribution = self.contract.functions.redistributions(1).call()
|
||||
self.assertEqual(2, self.contract.functions.toRedistributionPeriod(redistribution).call())
|
||||
self.assertEqual(2, self.contract.functions.actualPeriod().call())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -5,66 +5,104 @@ import json
|
||||
import logging
|
||||
import math
|
||||
|
||||
# external imports
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
from chainlib.eth.nonce import RPCNonceOracle
|
||||
from chainlib.eth.tx import receipt
|
||||
from chainlib.error import JSONRPCException
|
||||
# third-party imports
|
||||
import web3
|
||||
import eth_tester
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token import DemurrageToken
|
||||
|
||||
# test imports
|
||||
from tests.base import TestDemurrageDefault
|
||||
import eth_abi
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
logging.getLogger('web3').setLevel(logging.WARNING)
|
||||
logging.getLogger('eth.vm').setLevel(logging.WARNING)
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
#BLOCKTIME = 5 # seconds
|
||||
TAX_LEVEL = int((10000 * 2) * (10 ** 32)) # 2%
|
||||
PERIOD = 10
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
contract = None
|
||||
|
||||
def setUp(self):
|
||||
eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({
|
||||
'gas_limit': 9000000,
|
||||
})
|
||||
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.bin'), 'r')
|
||||
self.bytecode = f.read()
|
||||
f.close()
|
||||
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.json'), 'r')
|
||||
self.abi = json.load(f)
|
||||
f.close()
|
||||
|
||||
|
||||
backend = eth_tester.PyEVMBackend(eth_params)
|
||||
self.eth_tester = eth_tester.EthereumTester(backend)
|
||||
provider = web3.Web3.EthereumTesterProvider(self.eth_tester)
|
||||
self.w3 = web3.Web3(provider)
|
||||
self.sink_address = self.w3.eth.accounts[9]
|
||||
|
||||
c = self.w3.eth.contract(abi=self.abi, bytecode=self.bytecode)
|
||||
tx_hash = c.constructor('Foo Token', 'FOO', 6, TAX_LEVEL, PERIOD, self.sink_address).transact({'from': self.w3.eth.accounts[0]})
|
||||
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.contract = self.w3.eth.contract(abi=self.abi, address=r.contractAddress)
|
||||
|
||||
self.start_block = self.w3.eth.blockNumber
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
@unittest.skip('this function has been removed from contract')
|
||||
def test_tax_period(self):
|
||||
t = self.contract.functions.taxLevel().call()
|
||||
logg.debug('taxlevel {}'.format(t))
|
||||
|
||||
a = self.contract.functions.toDemurrageAmount(1000000, 0).call()
|
||||
self.assertEqual(a, 1000000)
|
||||
|
||||
a = self.contract.functions.toDemurrageAmount(1000000, 1).call()
|
||||
self.assertEqual(a, 980000)
|
||||
|
||||
a = self.contract.functions.toDemurrageAmount(1000000, 2).call()
|
||||
self.assertEqual(a, 960400)
|
||||
|
||||
a = self.contract.functions.toDemurrageAmount(980000, 1).call()
|
||||
self.assertEqual(a, 960400)
|
||||
|
||||
class Test(TestDemurrageDefault):
|
||||
|
||||
def test_fractional_state(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
self.contract.functions.remainder(2, 1).call();
|
||||
|
||||
with self.assertRaises(JSONRPCException):
|
||||
o = c.remainder(self.address, 2, 1, sender_address=self.accounts[0])
|
||||
self.rpc.do(o)
|
||||
|
||||
with self.assertRaises(JSONRPCException):
|
||||
o = c.remainder(self.address, 0, 100001, sender_address=self.accounts[0])
|
||||
self.rpc.do(o)
|
||||
with self.assertRaises(eth_tester.exceptions.TransactionFailed):
|
||||
remainder = self.contract.functions.remainder(0, 100001).call();
|
||||
|
||||
o = c.remainder(self.address, 1, 2, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
remainder = c.parse_remainder(r)
|
||||
remainder = self.contract.functions.remainder(1, 2).call();
|
||||
self.assertEqual(remainder, 0);
|
||||
|
||||
|
||||
whole = 5000001
|
||||
parts = 20000
|
||||
expect = whole - (math.floor(whole/parts) * parts)
|
||||
o = c.remainder(self.address, parts, whole, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
remainder = c.parse_remainder(r)
|
||||
remainder = self.contract.functions.remainder(parts, whole).call();
|
||||
self.assertEqual(remainder, expect)
|
||||
|
||||
parts = 30000
|
||||
expect = whole - (math.floor(whole/parts) * parts)
|
||||
o = c.remainder(self.address, parts, whole, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
remainder = c.parse_remainder(r)
|
||||
remainder = self.contract.functions.remainder(parts, whole).call();
|
||||
self.assertEqual(remainder, expect)
|
||||
|
||||
parts = 40001
|
||||
expect = whole - (math.floor(whole/parts) * parts)
|
||||
o = c.remainder(self.address, parts, whole, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
remainder = c.parse_remainder(r)
|
||||
remainder = self.contract.functions.remainder(parts, whole).call();
|
||||
self.assertEqual(remainder, expect)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -4,26 +4,17 @@ 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
|
||||
# third-party imports
|
||||
import web3
|
||||
import eth_tester
|
||||
import eth_abi
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
logging.getLogger('web3').setLevel(logging.WARNING)
|
||||
logging.getLogger('eth.vm').setLevel(logging.WARNING)
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
#BLOCKTIME = 5 # seconds
|
||||
@@ -32,235 +23,173 @@ TAX_LEVEL = 10000 * 2 # 2%
|
||||
PERIOD = 1
|
||||
|
||||
|
||||
class TestRedistribution(TestDemurrageDefault):
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def test_debug_periods(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
contract = None
|
||||
|
||||
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
pactual = c.parse_actual_period(r)
|
||||
def setUp(self):
|
||||
eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({
|
||||
'gas_limit': 9000000,
|
||||
})
|
||||
|
||||
o = c.period_start(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
pstart = c.parse_actual_period(r)
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.bin'), 'r')
|
||||
self.bytecode = f.read()
|
||||
f.close()
|
||||
|
||||
o = c.period_duration(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
pduration = c.parse_actual_period(r)
|
||||
f = open(os.path.join(testdir, '../../solidity/RedistributedDemurrageToken.json'), 'r')
|
||||
self.abi = json.load(f)
|
||||
f.close()
|
||||
|
||||
o = block_latest()
|
||||
blocknumber = self.rpc.do(o)
|
||||
backend = eth_tester.PyEVMBackend(eth_params)
|
||||
self.eth_tester = eth_tester.EthereumTester(backend)
|
||||
provider = web3.Web3.EthereumTesterProvider(self.eth_tester)
|
||||
self.w3 = web3.Web3(provider)
|
||||
self.sink_address = self.w3.eth.accounts[9]
|
||||
|
||||
c = self.w3.eth.contract(abi=self.abi, bytecode=self.bytecode)
|
||||
tx_hash = c.constructor('Foo Token', 'FOO', 6, TAX_LEVEL * (10 ** 32), PERIOD, self.sink_address).transact({'from': self.w3.eth.accounts[0]})
|
||||
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.contract = self.w3.eth.contract(abi=self.abi, address=r.contractAddress)
|
||||
|
||||
self.start_block = self.w3.eth.blockNumber
|
||||
b = self.w3.eth.getBlock(self.start_block)
|
||||
self.start_time = b['timestamp']
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
def debug_periods(self):
|
||||
pactual = self.contract.functions.actualPeriod().call()
|
||||
pstart = self.contract.functions.periodStart().call()
|
||||
pduration = self.contract.functions.periodDuration().call()
|
||||
blocknumber = self.w3.eth.blockNumber;
|
||||
logg.debug('actual {} start {} duration {} blocknumber {}'.format(pactual, pstart, pduration, blocknumber))
|
||||
|
||||
|
||||
# TODO: check receipt log outputs
|
||||
def test_redistribution_storage(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(strip_0x(r), '000000000000000000000000f424000000000000000000000000000000000001')
|
||||
redistribution = self.contract.functions.redistributions(0).call();
|
||||
self.assertEqual(redistribution.hex(), '000000000000000000000000f424000000000000000000000000000000000001')
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1000000)
|
||||
r = self.rpc.do(o)
|
||||
self.contract.functions.mintTo(self.w3.eth.accounts[1], 1000000).transact()
|
||||
self.contract.functions.mintTo(self.w3.eth.accounts[2], 1000000).transact()
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[2], 1000000)
|
||||
r = self.rpc.do(o)
|
||||
external_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex())
|
||||
tx_hash = self.contract.functions.transfer(external_address, 1000000).transact({'from': self.w3.eth.accounts[2]})
|
||||
tx_hash = self.contract.functions.transfer(external_address, 999999).transact({'from': self.w3.eth.accounts[1]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
logg.debug('tx before {}'.format(r))
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
external_address = to_checksum_address('0x' + os.urandom(20).hex())
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
|
||||
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[2], external_address, 1000000)
|
||||
r = self.rpc.do(o)
|
||||
redistribution = self.contract.functions.redistributions(0).call();
|
||||
self.assertEqual(redistribution.hex(), '000000000000000000000000f42400000000010000000000001e848000000001')
|
||||
|
||||
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], external_address, 999999)
|
||||
r = self.rpc.do(o)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
|
||||
o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(strip_0x(r), '000000000000000000000000f42400000000010000000000001e848000000001')
|
||||
|
||||
o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(strip_0x(r), '000000000000000000000000f42400000000010000000000001e848000000001')
|
||||
|
||||
|
||||
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[0], 1000000)
|
||||
r = self.rpc.do(o)
|
||||
|
||||
o = c.redistributions(self.address, 1, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(strip_0x(r), '000000000000000000000000ef4200000000000000000000002dc6c000000002')
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[0], 1000000).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
redistribution = self.contract.functions.redistributions(1).call()
|
||||
self.assertEqual(redistribution.hex(), '000000000000000000000000ef4200000000000000000000002dc6c000000002')
|
||||
|
||||
|
||||
def test_redistribution_balance_on_zero_participants(self):
|
||||
supply = 1000000000000
|
||||
tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], supply).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
|
||||
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], supply)
|
||||
r = self.rpc.do(o)
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
|
||||
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 = self.contract.functions.applyDemurrage().transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
logg.debug('r {}'.format(r))
|
||||
self.assertEqual(r.status, 1)
|
||||
tx_hash = self.contract.functions.changePeriod().transact()
|
||||
rr = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
self.assertEqual(rr.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)
|
||||
redistribution = self.contract.functions.redistributions(0).call();
|
||||
supply = self.contract.functions.totalSupply().call()
|
||||
|
||||
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))
|
||||
self.assertEqual(supply, total_supply)
|
||||
|
||||
for l in rcpt['logs']:
|
||||
if l['topics'][0] == '0xa0717e54e02bd9829db5e6e998aec0ae9de796b8d150a3cc46a92ab869697755': # event Decayed(uint256,uint256,uint256,uint256)
|
||||
period = int.from_bytes(bytes.fromhex(strip_0x(l['topics'][1])), 'big')
|
||||
sink_increment = int(supply * (TAX_LEVEL / 1000000))
|
||||
for l in r['logs']:
|
||||
if l.topics[0].hex() == '0xa0717e54e02bd9829db5e6e998aec0ae9de796b8d150a3cc46a92ab869697755': # event Decayed(uint256,uint256,uint256,uint256)
|
||||
period = int.from_bytes(l.topics[1], 'big')
|
||||
self.assertEqual(period, 2)
|
||||
b = bytes.fromhex(strip_0x(l['data']))
|
||||
b = bytes.fromhex(l.data[2:])
|
||||
remainder = int.from_bytes(b, 'big')
|
||||
self.assertEqual(remainder, int((1000000 - TAX_LEVEL) * (10 ** 32)))
|
||||
logg.debug('period {} remainder {}'.format(period, remainder))
|
||||
|
||||
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)
|
||||
|
||||
sink_balance = self.contract.functions.balanceOf(self.sink_address).call()
|
||||
logg.debug('{} {}'.format(sink_increment, sink_balance))
|
||||
self.assertEqual(sink_balance, int(sink_increment * 0.98))
|
||||
self.assertEqual(sink_balance, int(sink_increment * (1000000 - TAX_LEVEL) / 1000000))
|
||||
|
||||
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)
|
||||
balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
self.assertEqual(balance, supply - sink_increment)
|
||||
|
||||
|
||||
def test_redistribution_two_of_ten(self):
|
||||
mint_amount = 100000000
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
z = 0
|
||||
for i in range(10):
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[i], mint_amount)
|
||||
self.rpc.do(o)
|
||||
self.contract.functions.mintTo(self.w3.eth.accounts[i], mint_amount).transact()
|
||||
z += mint_amount
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
initial_balance = c.parse_balance_of(r)
|
||||
initial_balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
|
||||
spend_amount = 1000000
|
||||
external_address = to_checksum_address('0x' + os.urandom(20).hex())
|
||||
|
||||
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], external_address, spend_amount)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
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[2], external_address, spend_amount)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
external_address = web3.Web3.toChecksumAddress('0x' + os.urandom(20).hex())
|
||||
self.contract.functions.transfer(external_address, spend_amount).transact({'from': self.w3.eth.accounts[1]})
|
||||
tx_hash = self.contract.functions.transfer(external_address, spend_amount).transact({'from': self.w3.eth.accounts[2]})
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
# No cheating!
|
||||
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[3], self.accounts[3], spend_amount)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
self.contract.functions.transfer(self.w3.eth.accounts[3], spend_amount).transact({'from': self.w3.eth.accounts[3]})
|
||||
# No cheapskating!
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[4], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.transfer(self.address, self.accounts[4], external_address, spend_amount-1)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
self.contract.functions.transfer(external_address, spend_amount-1).transact({'from': self.w3.eth.accounts[4]})
|
||||
|
||||
self.assertEqual(r.status, 1)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
self.eth_tester.time_travel(self.start_time + 61)
|
||||
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, self.accounts[4])
|
||||
self.rpc.do(o)
|
||||
|
||||
(tx_hash, o) = c.change_period(self.address, self.accounts[4])
|
||||
self.rpc.do(o)
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
bummer_balance = c.parse_balance_of(r)
|
||||
self.contract.functions.applyDemurrage().transact()
|
||||
self.contract.functions.changePeriod().transact()
|
||||
|
||||
bummer_balance = self.contract.functions.balanceOf(self.w3.eth.accounts[3]).call()
|
||||
self.assertEqual(bummer_balance, mint_amount - (mint_amount * (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)
|
||||
bummer_balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
spender_balance = mint_amount - spend_amount
|
||||
spender_decayed_balance = int(spender_balance - (spender_balance * (TAX_LEVEL / 1000000)))
|
||||
self.assertEqual(bummer_balance, spender_decayed_balance)
|
||||
logg.debug('bal {} '.format(bummer_balance))
|
||||
|
||||
(tx_hash, o) = c.apply_redistribution_on_account(self.address, self.accounts[4], self.accounts[1])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
tx_hash = self.contract.functions.applyRedistributionOnAccount(self.w3.eth.accounts[1]).transact()
|
||||
r = self.w3.eth.getTransactionReceipt(tx_hash)
|
||||
logg.debug('log {}'.format(r.logs))
|
||||
|
||||
# logg.debug('log {}'.format(r.logs))
|
||||
(tx_hash, o) = c.apply_redistribution_on_account(self.address, self.accounts[4], self.accounts[2])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
self.contract.functions.applyRedistributionOnAccount(self.w3.eth.accounts[2]).transact()
|
||||
|
||||
o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
redistribution_data = c.parse_redistributions(r)
|
||||
logg.debug('redist data {}'.format(redistribution_data))
|
||||
redistribution_data = self.contract.functions.redistributions(0).call()
|
||||
logg.debug('redist data {}'.format(redistribution_data.hex()))
|
||||
|
||||
o = c.account_period(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
account_period_data = c.parse_account_period(r)
|
||||
account_period_data = self.contract.functions.accountPeriod(self.w3.eth.accounts[1]).call()
|
||||
logg.debug('account period {}'.format(account_period_data))
|
||||
|
||||
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
actual_period = c.parse_actual_period(r)
|
||||
actual_period = self.contract.functions.actualPeriod().call()
|
||||
logg.debug('period {}'.format(actual_period))
|
||||
|
||||
redistribution = int((z / 2) * (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)))
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
spender_actual_balance = c.parse_balance_of(r)
|
||||
spender_actual_balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
|
||||
logg.debug('rrr {} {}'.format(redistribution, spender_new_decayed_balance))
|
||||
|
||||
self.assertEqual(spender_actual_balance, spender_new_decayed_balance)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
SOLC = /usr/bin/solc
|
||||
|
||||
all:
|
||||
$(SOLC) DemurrageTokenMultiNocap.sol --abi --evm-version byzantium | awk 'NR>3' > DemurrageTokenMultiNocap.json
|
||||
$(SOLC) DemurrageTokenMultiNocap.sol --bin --evm-version byzantium | awk 'NR>3' > DemurrageTokenMultiNocap.bin
|
||||
truncate -s -1 DemurrageTokenMultiNocap.bin
|
||||
$(SOLC) RedistributedDemurrageToken.sol --abi --evm-version byzantium | awk 'NR>3' > RedistributedDemurrageToken.json
|
||||
$(SOLC) RedistributedDemurrageToken.sol --bin --evm-version byzantium | awk 'NR>3' > RedistributedDemurrageToken.bin
|
||||
truncate -s -1 RedistributedDemurrageToken.bin
|
||||
|
||||
test: all
|
||||
python ../python/tests/test_basic.py
|
||||
@@ -11,6 +11,6 @@ test: all
|
||||
python ../python/tests/test_redistribution.py
|
||||
|
||||
install: all
|
||||
cp -v DemurrageTokenMultiNocap.{json,bin} ../python/sarafu_token/data/
|
||||
cp -v RedistributedDemurrageToken.{json,bin} ../python/sarafu_token/data/
|
||||
|
||||
.PHONY: test install
|
||||
|
||||
Reference in New Issue
Block a user