Compare commits
3 Commits
master
...
lash/chain
Author | SHA1 | Date | |
---|---|---|---|
|
c7af21e233 | ||
|
276b346e52 | ||
|
6dc843fb5d |
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,5 +6,3 @@ __pycache__
|
||||
gmon.out
|
||||
solidity/*.json
|
||||
solidity/*.bin
|
||||
.venv
|
||||
venv
|
@ -1,36 +0,0 @@
|
||||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
|
||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
|
||||
# This specific template is located at:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Python.gitlab-ci.yml
|
||||
|
||||
# Official language image. Look for the different tagged releases at:
|
||||
# https://hub.docker.com/r/library/python/tags/
|
||||
image: python:3.8
|
||||
|
||||
# Change pip's cache directory to be inside the project directory since we can
|
||||
# only cache local items.
|
||||
variables:
|
||||
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
||||
|
||||
# Pip's cache doesn't store the python packages
|
||||
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
|
||||
#
|
||||
# If you want to also cache the installed packages, you have to install
|
||||
# them in a virtualenv and cache it as well.
|
||||
cache:
|
||||
paths:
|
||||
- .cache/pip
|
||||
- venv/
|
||||
|
||||
before_script:
|
||||
- cd ./python
|
||||
- python --version # For debugging
|
||||
- pip install virtualenv
|
||||
- virtualenv venv
|
||||
- source venv/bin/activate
|
||||
|
||||
test:
|
||||
script:
|
||||
- pip install -r requirements.txt -r test_requirements.txt --extra-index-url https://pip.grassrootseconomics.net
|
||||
- bash run_tests.sh
|
||||
|
@ -1,14 +1,7 @@
|
||||
- 0.1.1
|
||||
* Settable demurrage steps for apply demurrage cli tool
|
||||
- 0.1.0
|
||||
* Dependency upgrades
|
||||
- 0.0.11
|
||||
* Apply demurrage cli tool
|
||||
- 0.0.10
|
||||
* Settable sink address
|
||||
- 0.0.9
|
||||
* Correct redistribution amount for SingleNocap contract
|
||||
* Fix wrong redistribution calculation in single nocap
|
||||
[...]
|
||||
- 0.0.2
|
||||
* Move to chainlib-eth
|
||||
- 0.0.1
|
||||
- 0.0.1-unreleased
|
||||
* Interface for redistributed and non-redistributed, with or without cap
|
||||
|
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
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
@ -1,144 +0,0 @@
|
||||
"""Deploy sarafu token
|
||||
|
||||
.. moduleauthor:: Louis Holbrook <dev@holbrook.no>
|
||||
.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
|
||||
|
||||
"""
|
||||
|
||||
# standard imports
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import logging
|
||||
import datetime
|
||||
import math
|
||||
|
||||
# external imports
|
||||
import confini
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.nonce import (
|
||||
RPCNonceOracle,
|
||||
OverrideNonceOracle,
|
||||
)
|
||||
from chainlib.eth.gas import (
|
||||
RPCGasOracle,
|
||||
OverrideGasOracle,
|
||||
)
|
||||
from chainlib.eth.block import (
|
||||
block_latest,
|
||||
block_by_number,
|
||||
Block,
|
||||
)
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.tx import receipt
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
import chainlib.eth.cli
|
||||
from hexathon import to_int as hex_to_int
|
||||
|
||||
# local imports
|
||||
import erc20_demurrage_token
|
||||
from erc20_demurrage_token import (
|
||||
DemurrageToken,
|
||||
DemurrageTokenSettings,
|
||||
)
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(__file__)
|
||||
data_dir = os.path.join(script_dir, '..', 'data')
|
||||
|
||||
config_dir = os.path.join(data_dir, 'config')
|
||||
|
||||
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_argument('--steps', type=int, default=0, help='Max demurrage steps to apply per round')
|
||||
args = argparser.parse_args()
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_fee_limit=DemurrageToken.gas(), base_config_dir=config_dir)
|
||||
config.add(args.steps, '_STEPS', False)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
wallet = chainlib.eth.cli.Wallet()
|
||||
wallet.from_config(config)
|
||||
|
||||
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
|
||||
def main():
|
||||
o = block_latest()
|
||||
r = conn.do(o)
|
||||
|
||||
block_start_number = None
|
||||
try:
|
||||
block_start_number = hex_to_int(r)
|
||||
except TypeError:
|
||||
block_start_number = int(r)
|
||||
|
||||
o = block_by_number(block_start_number)
|
||||
r = conn.do(o)
|
||||
|
||||
block_start = Block(r)
|
||||
block_start_timestamp = block_start.timestamp
|
||||
block_start_datetime = datetime.datetime.fromtimestamp(block_start_timestamp)
|
||||
|
||||
gas_oracle = rpc.get_gas_oracle()
|
||||
c = DemurrageToken(chain_spec, gas_oracle=gas_oracle)
|
||||
o = c.demurrage_timestamp(config.get('_EXEC_ADDRESS'))
|
||||
r = conn.do(o)
|
||||
|
||||
demurrage_timestamp = None
|
||||
try:
|
||||
demurrage_timestamp = hex_to_int(r)
|
||||
except TypeError:
|
||||
demurrage_timestamp = int(r)
|
||||
demurrage_datetime = datetime.datetime.fromtimestamp(demurrage_timestamp)
|
||||
|
||||
total_seconds = block_start_timestamp - demurrage_timestamp
|
||||
total_steps = total_seconds / 60
|
||||
|
||||
if total_steps < 1.0:
|
||||
logg.error('only {} seconds since last demurrage application, skipping'.format(total_seconds))
|
||||
return
|
||||
|
||||
logg.debug('block start is at {} demurrage is at {} -> {} minutes'.format(
|
||||
block_start_datetime,
|
||||
demurrage_datetime,
|
||||
total_steps,
|
||||
))
|
||||
|
||||
rounds = 1
|
||||
if config.get('_STEPS') > 0:
|
||||
rounds = math.ceil(total_steps / config.get('_STEPS'))
|
||||
|
||||
logg.info('will perform {} rounds of {} steps'.format(rounds, config.get('_STEPS')))
|
||||
|
||||
last_tx_hash = None
|
||||
for i in range(rounds):
|
||||
signer = rpc.get_signer()
|
||||
signer_address = rpc.get_sender_address()
|
||||
|
||||
nonce_oracle = rpc.get_nonce_oracle()
|
||||
|
||||
c = DemurrageToken(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
|
||||
(tx_hash_hex, o) = c.apply_demurrage(config.get('_EXEC_ADDRESS'), signer_address, limit=config.get('_STEPS'))
|
||||
if config.get('_RPC_SEND'):
|
||||
print(tx_hash_hex)
|
||||
conn.do(o)
|
||||
if config.get('_WAIT_ALL') or (i == rounds - 1 and config.get('_WAIT')):
|
||||
r = conn.wait(tx_hash_hex)
|
||||
if r['status'] == 0:
|
||||
sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you')
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(o)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -49,8 +49,8 @@ arg_flags = chainlib.eth.cli.argflag_std_write
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_argument('--name', dest='token_name', type=str, help='Token name')
|
||||
argparser.add_argument('--symbol', dest='token_symbol', required=True, type=str, help='Token symbol')
|
||||
argparser.add_argument('--decimals', dest='token_decimals', type=int, help='Token decimals')
|
||||
argparser.add_argument('--sink-address', dest='sink_address', type=str, help='demurrage level,ppm per minute')
|
||||
argparser.add_argument('--decimals', dest='token_decimals', default=18, type=int, help='Token decimals')
|
||||
argparser.add_argument('--sink-address', dest='sink_address', default=ZERO_ADDRESS, type=str, help='demurrage level,ppm per minute')
|
||||
argparser.add_argument('--supply-limit', dest='supply_limit', type=int, help='token supply limit (0 = no limit)')
|
||||
argparser.add_argument('--redistribution-period', type=int, help='redistribution period, minutes (0 = deactivate)') # default 10080 = week
|
||||
argparser.add_argument('--multi', action='store_true', help='automatic redistribution')
|
||||
@ -90,6 +90,7 @@ conn = rpc.connect_by_config(config)
|
||||
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
|
||||
def main():
|
||||
signer = rpc.get_signer()
|
||||
signer_address = rpc.get_sender_address()
|
||||
|
@ -38,15 +38,6 @@ class DemurrageTokenSettings:
|
||||
self.sink_address = None
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return 'name {} demurrage level {} period minutes {} sink address {}'.format(
|
||||
self.name,
|
||||
self.demurrage_level,
|
||||
self.period_minutes,
|
||||
self.sink_address,
|
||||
)
|
||||
|
||||
|
||||
class DemurrageToken(ERC20):
|
||||
|
||||
__abi = {}
|
||||
@ -389,10 +380,6 @@ class DemurrageToken(ERC20):
|
||||
return self.call_noarg('demurrageAmount', contract_address, sender_address=sender_address)
|
||||
|
||||
|
||||
def demurrage_timestamp(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||
return self.call_noarg('demurrageTimestamp', contract_address, sender_address=sender_address)
|
||||
|
||||
|
||||
def supply_cap(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||
return self.call_noarg('supplyCap', contract_address, sender_address=sender_address)
|
||||
|
||||
|
@ -32,19 +32,18 @@ PERIOD = 10
|
||||
|
||||
class TestTokenDeploy:
|
||||
|
||||
def __init__(self, rpc, token_symbol='FOO', token_name='Foo Token', sink_address=ZERO_ADDRESS, supply=10**12, tax_level=TAX_LEVEL, period=PERIOD):
|
||||
self.tax_level = tax_level
|
||||
self.period_seconds = period * 60
|
||||
def __init__(self, rpc, token_symbol='FOO', token_name='Foo Token', sink_address=ZERO_ADDRESS, supply=10**12):
|
||||
self.tax_level = TAX_LEVEL
|
||||
self.period_seconds = PERIOD * 60
|
||||
|
||||
self.settings = DemurrageTokenSettings()
|
||||
self.settings.name = token_name
|
||||
self.settings.symbol = token_symbol
|
||||
self.settings.decimals = 6
|
||||
self.settings.demurrage_level = tax_level * (10 ** 32)
|
||||
self.settings.period_minutes = period
|
||||
self.settings.demurrage_level = TAX_LEVEL * (10 ** 32)
|
||||
self.settings.period_minutes = PERIOD
|
||||
self.settings.sink_address = sink_address
|
||||
self.sink_address = self.settings.sink_address
|
||||
logg.debug('using demurrage token settings: {}'.format(self.settings))
|
||||
|
||||
o = block_latest()
|
||||
self.start_block = rpc.do(o)
|
||||
@ -102,12 +101,7 @@ class TestDemurrage(EthTesterCase):
|
||||
# self.start_time = token_deploy.start_time
|
||||
# self.default_supply = self.default_supply
|
||||
# self.default_supply_cap = self.default_supply_cap
|
||||
period = PERIOD
|
||||
try:
|
||||
period = getattr(self, 'period')
|
||||
except AttributeError as e:
|
||||
pass
|
||||
self.deployer = TestTokenDeploy(self.rpc, period=period)
|
||||
self.deployer = TestTokenDeploy(self.rpc)
|
||||
self.default_supply = self.deployer.default_supply
|
||||
self.default_supply_cap = self.deployer.default_supply_cap
|
||||
self.start_block = None
|
||||
@ -209,11 +203,10 @@ class TestDemurrageCap(TestDemurrage):
|
||||
class TestDemurrageUnit(TestDemurrage):
|
||||
|
||||
def setUp(self):
|
||||
self.period = 1
|
||||
self.period_seconds = self.period * 60
|
||||
self.tax_level = TAX_LEVEL
|
||||
super(TestDemurrage, self).setUp()
|
||||
|
||||
super(TestDemurrageUnit, self).setUp()
|
||||
self.tax_level = 50
|
||||
self.period_seconds = 60
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
self.settings = DemurrageTokenSettings()
|
||||
|
@ -1,3 +1,3 @@
|
||||
chainlib-eth>=0.1.0,<0.2.0
|
||||
eth-erc20~=0.3.0
|
||||
funga-eth~=0.6.0
|
||||
chainlib-eth>=0.0.27,<=0.1.0
|
||||
eth-erc20~=0.1.11
|
||||
funga-eth~=0.5.6
|
||||
|
@ -17,12 +17,7 @@ done
|
||||
modes=(SingleCap) # other contracts need to be updted
|
||||
for m in ${modes[@]}; do
|
||||
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py
|
||||
done
|
||||
|
||||
modes=(SingleNocap) # other contracts need to be updted
|
||||
for m in ${modes[@]}; do
|
||||
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py
|
||||
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_single.py
|
||||
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py
|
||||
done
|
||||
|
||||
modes=(MultiCap SingleCap)
|
||||
|
@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = erc20-demurrage-token
|
||||
version = 0.1.1
|
||||
version = 0.1.0
|
||||
description = ERC20 token with redistributed continual demurrage
|
||||
author = Louis Holbrook
|
||||
author_email = dev@holbrook.no
|
||||
@ -25,13 +25,12 @@ licence_files =
|
||||
|
||||
[options]
|
||||
include_package_data = True
|
||||
python_requires = >= 3.7
|
||||
python_requires = >= 3.6
|
||||
packages =
|
||||
erc20_demurrage_token
|
||||
erc20_demurrage_token.runnable
|
||||
erc20_demurrage_token.data
|
||||
erc20_demurrage_token.sim
|
||||
erc20_demurrage_token.unittest
|
||||
|
||||
[options.package_data]
|
||||
* =
|
||||
@ -41,4 +40,3 @@ packages =
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
erc20-demurrage-token-deploy = erc20_demurrage_token.runnable.deploy:main
|
||||
erc20-demurrage-token-apply = erc20_demurrage_token.runnable.apply:main
|
||||
|
@ -80,6 +80,7 @@ class TestBasic(TestDemurrageDefault):
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
|
||||
|
||||
|
||||
def test_apply_demurrage(self):
|
||||
modifier = (10 ** 28)
|
||||
|
||||
|
@ -7,15 +7,7 @@ import logging
|
||||
# external imports
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
from chainlib.eth.nonce import RPCNonceOracle
|
||||
from chainlib.eth.tx import (
|
||||
receipt,
|
||||
TxFactory,
|
||||
TxFormat,
|
||||
)
|
||||
from chainlib.eth.contract import (
|
||||
ABIContractEncoder,
|
||||
ABIContractType,
|
||||
)
|
||||
from chainlib.eth.tx import receipt
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token import DemurrageToken
|
||||
@ -111,90 +103,5 @@ class TestPeriod(TestDemurrageDefault):
|
||||
self.assertEqual(modifier, period)
|
||||
|
||||
|
||||
def test_change_sink(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
o = c.balance_of(self.address, ZERO_ADDRESS, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance_of(r)
|
||||
self.assertEqual(balance, 0)
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 102400000000)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
self.backend.time_travel(self.start_time + self.period_seconds + 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.balance_of(self.address, ZERO_ADDRESS, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance_of(r)
|
||||
self.assertGreater(balance, 0)
|
||||
old_sink_balance = balance
|
||||
|
||||
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, 0)
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[5], self.rpc)
|
||||
c = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('setSinkAddress')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(self.accounts[3])
|
||||
data = enc.get()
|
||||
o = c.template(self.accounts[5], self.address, use_nonce=True)
|
||||
o = c.set_code(o, data)
|
||||
(tx_hash, o) = c.finalize(o, TxFormat.JSONRPC)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 0)
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('setSinkAddress')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.address(self.accounts[3])
|
||||
data = enc.get()
|
||||
o = c.template(self.accounts[0], self.address, use_nonce=True)
|
||||
o = c.set_code(o, data)
|
||||
(tx_hash, o) = c.finalize(o, TxFormat.JSONRPC)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
self.backend.time_travel(self.start_time + (self.period_seconds * 2) + 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.balance_of(self.address, ZERO_ADDRESS, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance_of(r)
|
||||
self.assertLess(balance, old_sink_balance)
|
||||
|
||||
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.assertGreater(balance, 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -31,8 +31,6 @@ testdir = os.path.dirname(__file__)
|
||||
|
||||
class TestRedistribution(TestDemurrageDefault):
|
||||
|
||||
|
||||
|
||||
def test_whole_is_parts(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
@ -1,185 +0,0 @@
|
||||
# standard imports
|
||||
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,
|
||||
block_by_number,
|
||||
)
|
||||
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 erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
testdir = os.path.dirname(__file__)
|
||||
|
||||
class TestRedistribution(TestDemurrageDefault):
|
||||
|
||||
|
||||
def test_redistribution_periods(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
|
||||
supply = self.default_supply
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[0], supply)
|
||||
self.rpc.do(o)
|
||||
|
||||
for i in range(1, 10):
|
||||
logg.debug('execute time travel to period {}'.format(i))
|
||||
self.backend.time_travel(self.start_time + (self.period_seconds * i))
|
||||
(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)
|
||||
|
||||
o = c.redistributions(self.address, i, sender_address=self.accounts[0])
|
||||
redistribution = self.rpc.do(o)
|
||||
|
||||
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage = c.parse_to_redistribution_item(r)
|
||||
|
||||
o = c.redistributions(self.address, i-1, sender_address=self.accounts[0])
|
||||
redistribution = self.rpc.do(o)
|
||||
|
||||
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_previous = c.parse_to_redistribution_item(r)
|
||||
|
||||
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance_sink = c.parse_balance(r)
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[0], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance_minter = c.parse_balance(r)
|
||||
|
||||
logg.debug('testing sink {} mint {} adds up to supply {} with demurrage between {} and {}'.format(balance_sink, balance_minter, supply, demurrage_previous, demurrage))
|
||||
|
||||
self.assert_within_lower(balance_minter + balance_sink, supply, 0.001)
|
||||
|
||||
|
||||
def test_redistribution_catchup_periods(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
|
||||
supply = self.default_supply
|
||||
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[0], supply)
|
||||
self.rpc.do(o)
|
||||
|
||||
self.backend.time_travel(self.start_time + (self.period_seconds * 10))
|
||||
|
||||
for i in range(1, 11):
|
||||
logg.debug('checking period {}'.format(i))
|
||||
|
||||
(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)
|
||||
|
||||
i = 10
|
||||
o = c.redistributions(self.address, i, sender_address=self.accounts[0])
|
||||
redistribution = self.rpc.do(o)
|
||||
|
||||
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage = c.parse_to_redistribution_item(r)
|
||||
|
||||
o = c.redistributions(self.address, i-1, sender_address=self.accounts[0])
|
||||
redistribution = self.rpc.do(o)
|
||||
|
||||
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_previous = c.parse_to_redistribution_item(r)
|
||||
|
||||
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance_sink = c.parse_balance(r)
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[0], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance_minter = c.parse_balance(r)
|
||||
|
||||
logg.debug('testing sink {} mint {} adds up to supply {} with demurrage between {} and {}'.format(balance_sink, balance_minter, supply, demurrage_previous, demurrage))
|
||||
|
||||
self.assert_within_lower(balance_minter + balance_sink, supply, 0.001)
|
||||
|
||||
|
||||
# def test_redistribution_boundaries(self):
|
||||
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
#
|
||||
# demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
|
||||
# supply = self.default_supply
|
||||
#
|
||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[0], supply)
|
||||
# self.rpc.do(o)
|
||||
#
|
||||
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
|
||||
# r = self.rpc.do(o)
|
||||
# balance = c.parse_balance(r)
|
||||
# logg.debug('balance before {} supply {}'.format(balance, supply))
|
||||
#
|
||||
# self.backend.time_travel(self.start_time + self.period_seconds)
|
||||
# (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)
|
||||
# oo = c.to_redistribution_supply(self.address, r, sender_address=self.accounts[0])
|
||||
# rr = self.rpc.do(oo)
|
||||
# oo = c.to_redistribution_demurrage_modifier(self.address, r, sender_address=self.accounts[0])
|
||||
# rr = self.rpc.do(oo)
|
||||
#
|
||||
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
|
||||
# r = self.rpc.do(o)
|
||||
# balance = c.parse_balance(r)
|
||||
#
|
||||
# self.backend.time_travel(self.start_time + self.period_seconds * 2 + 1)
|
||||
# (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, 2, sender_address=self.accounts[0])
|
||||
# r = self.rpc.do(o)
|
||||
# oo = c.to_redistribution_supply(self.address, r, sender_address=self.accounts[0])
|
||||
# rr = self.rpc.do(oo)
|
||||
# oo = c.to_redistribution_demurrage_modifier(self.address, r, sender_address=self.accounts[0])
|
||||
# rr = self.rpc.do(oo)
|
||||
#
|
||||
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
|
||||
# r = self.rpc.do(o)
|
||||
# balance = c.parse_balance(r)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -31,12 +31,12 @@ testdir = os.path.dirname(__file__)
|
||||
|
||||
class TestRedistribution(TestDemurrageUnit):
|
||||
|
||||
|
||||
# TODO: move to "pure" test file when getdistribution is implemented in all contracts
|
||||
def test_distribution_direct(self):
|
||||
def test_distribution(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
#demurrage = (1 - (self.tax_level / 1000000)) * (10**38)
|
||||
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
|
||||
supply = self.default_supply
|
||||
|
||||
@ -51,23 +51,21 @@ class TestRedistribution(TestDemurrageUnit):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
demurrage = (1 - (self.tax_level / 100000)) * (10**28)
|
||||
|
||||
logg.debug('demurrage {}'.format(demurrage))
|
||||
#demurrage = (1 - (self.tax_level / 1000000)) * (10**38)
|
||||
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
|
||||
supply = self.default_supply
|
||||
|
||||
o = c.to_redistribution(self.address, 0, demurrage, supply, 2, sender_address=self.accounts[0])
|
||||
o = c.to_redistribution(self.address, 0, demurrage, supply, 1, sender_address=self.accounts[0])
|
||||
redistribution = self.rpc.do(o)
|
||||
|
||||
o = c.get_distribution_from_redistribution(self.address, redistribution, self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
distribution = c.parse_get_distribution(r)
|
||||
expected_distribution = (self.default_supply * self.tax_level) / 100000
|
||||
logg.debug('distribution {} supply {}'.format(distribution, self.default_supply))
|
||||
expected_distribution = self.default_supply * (self.tax_level / 1000000)
|
||||
self.assert_within_lower(distribution, expected_distribution, 1000)
|
||||
|
||||
|
||||
def test_single_step_basic(self):
|
||||
def test_single_step(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
@ -83,12 +81,6 @@ class TestRedistribution(TestDemurrageUnit):
|
||||
|
||||
expected_balance = int(mint_amount - ((self.tax_level / 1000000) * mint_amount))
|
||||
|
||||
o = c.balance_of(self.address, ZERO_ADDRESS, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance(r)
|
||||
|
||||
logg.debug('balance {}'.format(balance))
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance(r)
|
||||
@ -183,6 +175,9 @@ class TestRedistribution(TestDemurrageUnit):
|
||||
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage = c.parse_to_redistribution_item(r)
|
||||
# o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||
# r = self.rpc.do(o)
|
||||
# demurrage = c.parse_demurrage_amount(r)
|
||||
logg.debug('\nrediistribution {}\ndemurrage {}\nsupply {}'.format(redistribution, demurrage, supply))
|
||||
|
||||
expected_balance = int(supply * (self.tax_level / 1000000))
|
||||
|
@ -128,12 +128,6 @@ contract DemurrageTokenSingleCap {
|
||||
minimumParticipantSpend = 10 ** uint256(_decimals);
|
||||
}
|
||||
|
||||
// Change sink address for redistribution
|
||||
function setSinkAddress(address _sinkAddress) public {
|
||||
require(msg.sender == owner);
|
||||
sinkAddress = _sinkAddress;
|
||||
}
|
||||
|
||||
// Given address will be allowed to call the mintTo() function
|
||||
function addMinter(address _minter) public returns (bool) {
|
||||
require(msg.sender == owner);
|
||||
|
@ -20,6 +20,8 @@ contract DemurrageTokenSingleCap {
|
||||
// Cached demurrage amount, ppm with 38 digit resolution
|
||||
uint128 public demurrageAmount;
|
||||
|
||||
// Cached demurrage period; the period for which demurrageAmount was calculated
|
||||
//uint128 public demurragePeriod;
|
||||
// Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
|
||||
uint256 public demurrageTimestamp;
|
||||
|
||||
@ -40,11 +42,8 @@ contract DemurrageTokenSingleCap {
|
||||
// Implements ERC20
|
||||
uint256 public totalSupply;
|
||||
|
||||
// Last executed period
|
||||
uint256 public lastPeriod;
|
||||
|
||||
// Last sink redistribution amount
|
||||
uint256 public totalSink;
|
||||
// Minimum amount of (demurraged) tokens an account must spend to participate in redistribution for a particular period
|
||||
uint256 public minimumParticipantSpend;
|
||||
|
||||
// 128 bit resolution of the demurrage divisor
|
||||
// (this constant x 1000000 is contained within 128 bits)
|
||||
@ -72,7 +71,7 @@ contract DemurrageTokenSingleCap {
|
||||
mapping (address => mapping (address => uint256 ) ) allowance; // holder -> spender -> amount (amount is subject to demurrage)
|
||||
|
||||
// Address to send unallocated redistribution tokens
|
||||
address public sinkAddress;
|
||||
address sinkAddress;
|
||||
|
||||
// Implements ERC20
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
@ -112,20 +111,17 @@ contract DemurrageTokenSingleCap {
|
||||
demurrageTimestamp = block.timestamp;
|
||||
periodStart = demurrageTimestamp;
|
||||
periodDuration = _periodMinutes * 60;
|
||||
demurrageAmount = uint128(nanoDivider) * 100;
|
||||
//demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor
|
||||
//demurrageAmount = 100000000000000000000000000000000000000;
|
||||
demurrageAmount = 10000000000000000000000000000;
|
||||
//demurragePeriod = 1;
|
||||
taxLevel = _taxLevelMinute; // Represents 38 decimal places
|
||||
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
|
||||
redistributions.push(initialRedistribution);
|
||||
|
||||
// Misc settings
|
||||
sinkAddress = _defaultSinkAddress;
|
||||
}
|
||||
|
||||
|
||||
// Change sink address for redistribution
|
||||
function setSinkAddress(address _sinkAddress) public {
|
||||
require(msg.sender == owner);
|
||||
sinkAddress = _sinkAddress;
|
||||
minimumParticipantSpend = 10 ** uint256(_decimals);
|
||||
}
|
||||
|
||||
// Given address will be allowed to call the mintTo() function
|
||||
@ -150,8 +146,10 @@ contract DemurrageTokenSingleCap {
|
||||
|
||||
baseBalance = baseBalanceOf(_account);
|
||||
|
||||
//periodCount = actualPeriod() - demurragePeriod;
|
||||
periodCount = getMinutesDelta(demurrageTimestamp);
|
||||
|
||||
//currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
|
||||
currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount));
|
||||
|
||||
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
|
||||
@ -249,6 +247,7 @@ contract DemurrageTokenSingleCap {
|
||||
uint256 currentRedistribution;
|
||||
uint256 grownSupply;
|
||||
|
||||
//grownSupply = growBy(totalSupply, 1);
|
||||
grownSupply = totalSupply;
|
||||
currentRedistribution = uint256(redistributions[redistributions.length-1]);
|
||||
currentRedistribution &= (~maskRedistributionValue);
|
||||
@ -268,7 +267,7 @@ contract DemurrageTokenSingleCap {
|
||||
bytes32 lastRedistribution;
|
||||
uint256 currentPeriod;
|
||||
|
||||
lastRedistribution = redistributions[lastPeriod];
|
||||
lastRedistribution = redistributions[redistributions.length-1];
|
||||
currentPeriod = this.actualPeriod();
|
||||
if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
|
||||
return bytes32(0x00);
|
||||
@ -279,7 +278,8 @@ contract DemurrageTokenSingleCap {
|
||||
function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
|
||||
uint256 difference;
|
||||
|
||||
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000));
|
||||
//difference = _supply * (resolutionFactor - _demurrageAmount); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
|
||||
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000)); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
|
||||
return difference / resolutionFactor;
|
||||
}
|
||||
|
||||
@ -295,13 +295,9 @@ contract DemurrageTokenSingleCap {
|
||||
// Returns the amount sent to the sink address
|
||||
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
|
||||
uint256 unit;
|
||||
uint256 baseUnit;
|
||||
|
||||
unit = getDistributionFromRedistribution(_redistribution);
|
||||
baseUnit = toBaseAmount(unit) - totalSink;
|
||||
increaseBaseBalance(sinkAddress, baseUnit);
|
||||
lastPeriod += 1;
|
||||
totalSink += baseUnit;
|
||||
increaseBaseBalance(sinkAddress, toBaseAmount(unit));
|
||||
return unit;
|
||||
}
|
||||
|
||||
@ -316,9 +312,13 @@ contract DemurrageTokenSingleCap {
|
||||
}
|
||||
|
||||
function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
|
||||
//uint128 epochPeriodCount;
|
||||
uint256 periodCount;
|
||||
uint256 lastDemurrageAmount;
|
||||
|
||||
//epochPeriodCount = actualPeriod();
|
||||
//periodCount = epochPeriodCount - demurragePeriod;
|
||||
|
||||
periodCount = getMinutesDelta(demurrageTimestamp);
|
||||
if (periodCount == 0) {
|
||||
return false;
|
||||
@ -416,6 +416,7 @@ contract DemurrageTokenSingleCap {
|
||||
|
||||
// Inflates the given amount according to the current demurrage modifier
|
||||
function toBaseAmount(uint256 _value) public view returns (uint256) {
|
||||
//return (_value * resolutionFactor) / demurrageAmount;
|
||||
return (_value * resolutionFactor) / (demurrageAmount * 10000000000);
|
||||
}
|
||||
|
||||
@ -466,6 +467,7 @@ contract DemurrageTokenSingleCap {
|
||||
decreaseBaseBalance(_from, _value);
|
||||
increaseBaseBalance(_to, _value);
|
||||
|
||||
//period = actualPeriod();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user