Runaway redistribution

This commit is contained in:
Louis Holbrook 2022-05-30 07:53:22 +00:00 committed by Mohamed Sohail
parent 226f81fc5c
commit 20e3a783fd
16 changed files with 338 additions and 71 deletions

View File

@ -1,3 +1,7 @@
- 0.1.1
* Settable demurrage steps for apply demurrage cli tool
- 0.1.0
* Dependency upgrades
- 0.0.11 - 0.0.11
* Apply demurrage cli tool * Apply demurrage cli tool
- 0.0.10 - 0.0.10

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

View File

@ -11,6 +11,8 @@ import os
import json import json
import argparse import argparse
import logging import logging
import datetime
import math
# external imports # external imports
import confini import confini
@ -25,10 +27,16 @@ from chainlib.eth.gas import (
RPCGasOracle, RPCGasOracle,
OverrideGasOracle, OverrideGasOracle,
) )
from chainlib.eth.block import (
block_latest,
block_by_number,
Block,
)
from chainlib.eth.connection import EthHTTPConnection from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import receipt from chainlib.eth.tx import receipt
from chainlib.eth.constant import ZERO_ADDRESS from chainlib.eth.constant import ZERO_ADDRESS
import chainlib.eth.cli import chainlib.eth.cli
from hexathon import to_int as hex_to_int
# local imports # local imports
import erc20_demurrage_token import erc20_demurrage_token
@ -47,8 +55,11 @@ config_dir = os.path.join(data_dir, 'config')
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
argparser = chainlib.eth.cli.ArgumentParser(arg_flags) 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() 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 = 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 = chainlib.eth.cli.Wallet()
wallet.from_config(config) wallet.from_config(config)
@ -60,30 +71,73 @@ chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
def main(): def main():
signer = rpc.get_signer() o = block_latest()
signer_address = rpc.get_sender_address() 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() gas_oracle = rpc.get_gas_oracle()
nonce_oracle = rpc.get_nonce_oracle() c = DemurrageToken(chain_spec, gas_oracle=gas_oracle)
o = c.demurrage_timestamp(config.get('_EXEC_ADDRESS'))
r = conn.do(o)
c = DemurrageToken(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) demurrage_timestamp = None
(tx_hash_hex, o) = c.apply_demurrage(config.get('_EXEC_ADDRESS'), signer_address) try:
if config.get('_RPC_SEND'): demurrage_timestamp = hex_to_int(r)
conn.do(o) except TypeError:
if config.get('_WAIT'): demurrage_timestamp = int(r)
r = conn.wait(tx_hash_hex) demurrage_datetime = datetime.datetime.fromtimestamp(demurrage_timestamp)
if r['status'] == 0:
sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you')
sys.exit(1)
# TODO: pass through translator for keys (evm tester uses underscore instead of camelcase)
address = r['contractAddress']
print(address) total_seconds = block_start_timestamp - demurrage_timestamp
else: 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) 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)
else:
print(o)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -38,6 +38,15 @@ class DemurrageTokenSettings:
self.sink_address = None 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): class DemurrageToken(ERC20):
__abi = {} __abi = {}
@ -380,6 +389,10 @@ class DemurrageToken(ERC20):
return self.call_noarg('demurrageAmount', contract_address, sender_address=sender_address) 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): def supply_cap(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('supplyCap', contract_address, sender_address=sender_address) return self.call_noarg('supplyCap', contract_address, sender_address=sender_address)

View File

@ -32,18 +32,19 @@ PERIOD = 10
class TestTokenDeploy: class TestTokenDeploy:
def __init__(self, rpc, token_symbol='FOO', token_name='Foo Token', sink_address=ZERO_ADDRESS, supply=10**12): 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.tax_level = tax_level
self.period_seconds = PERIOD * 60 self.period_seconds = period * 60
self.settings = DemurrageTokenSettings() self.settings = DemurrageTokenSettings()
self.settings.name = token_name self.settings.name = token_name
self.settings.symbol = token_symbol self.settings.symbol = token_symbol
self.settings.decimals = 6 self.settings.decimals = 6
self.settings.demurrage_level = TAX_LEVEL * (10 ** 32) self.settings.demurrage_level = tax_level * (10 ** 32)
self.settings.period_minutes = PERIOD self.settings.period_minutes = period
self.settings.sink_address = sink_address self.settings.sink_address = sink_address
self.sink_address = self.settings.sink_address self.sink_address = self.settings.sink_address
logg.debug('using demurrage token settings: {}'.format(self.settings))
o = block_latest() o = block_latest()
self.start_block = rpc.do(o) self.start_block = rpc.do(o)
@ -101,7 +102,12 @@ class TestDemurrage(EthTesterCase):
# self.start_time = token_deploy.start_time # self.start_time = token_deploy.start_time
# self.default_supply = self.default_supply # self.default_supply = self.default_supply
# self.default_supply_cap = self.default_supply_cap # self.default_supply_cap = self.default_supply_cap
self.deployer = TestTokenDeploy(self.rpc) period = PERIOD
try:
period = getattr(self, 'period')
except AttributeError as e:
pass
self.deployer = TestTokenDeploy(self.rpc, period=period)
self.default_supply = self.deployer.default_supply self.default_supply = self.deployer.default_supply
self.default_supply_cap = self.deployer.default_supply_cap self.default_supply_cap = self.deployer.default_supply_cap
self.start_block = None self.start_block = None
@ -203,10 +209,11 @@ class TestDemurrageCap(TestDemurrage):
class TestDemurrageUnit(TestDemurrage): class TestDemurrageUnit(TestDemurrage):
def setUp(self): def setUp(self):
super(TestDemurrage, self).setUp() self.period = 1
self.period_seconds = self.period * 60
self.tax_level = TAX_LEVEL
self.tax_level = 50 super(TestDemurrageUnit, self).setUp()
self.period_seconds = 60
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
self.settings = DemurrageTokenSettings() self.settings = DemurrageTokenSettings()

View File

@ -1,3 +1,3 @@
chainlib-eth~=0.0.27 chainlib-eth>=0.1.0,<0.2.0
eth-erc20~=0.1.10 eth-erc20~=0.3.0
funga-eth~=0.5.6 funga-eth~=0.6.0

View File

@ -17,7 +17,12 @@ done
modes=(SingleCap) # other contracts need to be updted modes=(SingleCap) # other contracts need to be updted
for m in ${modes[@]}; do for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.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
done done
modes=(MultiCap SingleCap) modes=(MultiCap SingleCap)

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = erc20-demurrage-token name = erc20-demurrage-token
version = 0.0.11 version = 0.1.1
description = ERC20 token with redistributed continual demurrage description = ERC20 token with redistributed continual demurrage
author = Louis Holbrook author = Louis Holbrook
author_email = dev@holbrook.no author_email = dev@holbrook.no
@ -25,12 +25,13 @@ licence_files =
[options] [options]
include_package_data = True include_package_data = True
python_requires = >= 3.6 python_requires = >= 3.7
packages = packages =
erc20_demurrage_token erc20_demurrage_token
erc20_demurrage_token.runnable erc20_demurrage_token.runnable
erc20_demurrage_token.data erc20_demurrage_token.data
erc20_demurrage_token.sim erc20_demurrage_token.sim
erc20_demurrage_token.unittest
[options.package_data] [options.package_data]
* = * =

View File

@ -31,6 +31,8 @@ testdir = os.path.dirname(__file__)
class TestRedistribution(TestDemurrageDefault): class TestRedistribution(TestDemurrageDefault):
def test_whole_is_parts(self): def test_whole_is_parts(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)

View File

@ -0,0 +1,185 @@
# 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()

View File

@ -31,12 +31,12 @@ testdir = os.path.dirname(__file__)
class TestRedistribution(TestDemurrageUnit): class TestRedistribution(TestDemurrageUnit):
# TODO: move to "pure" test file when getdistribution is implemented in all contracts # TODO: move to "pure" test file when getdistribution is implemented in all contracts
def test_distribution(self): def test_distribution_direct(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) 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) demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
supply = self.default_supply supply = self.default_supply
@ -51,21 +51,23 @@ class TestRedistribution(TestDemurrageUnit):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) 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 / 100000)) * (10**28)
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
logg.debug('demurrage {}'.format(demurrage))
supply = self.default_supply supply = self.default_supply
o = c.to_redistribution(self.address, 0, demurrage, supply, 1, sender_address=self.accounts[0]) o = c.to_redistribution(self.address, 0, demurrage, supply, 2, sender_address=self.accounts[0])
redistribution = self.rpc.do(o) redistribution = self.rpc.do(o)
o = c.get_distribution_from_redistribution(self.address, redistribution, self.accounts[0]) o = c.get_distribution_from_redistribution(self.address, redistribution, self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
distribution = c.parse_get_distribution(r) distribution = c.parse_get_distribution(r)
expected_distribution = self.default_supply * (self.tax_level / 1000000) expected_distribution = (self.default_supply * self.tax_level) / 100000
logg.debug('distribution {} supply {}'.format(distribution, self.default_supply))
self.assert_within_lower(distribution, expected_distribution, 1000) self.assert_within_lower(distribution, expected_distribution, 1000)
def test_single_step(self): def test_single_step_basic(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
@ -81,6 +83,12 @@ class TestRedistribution(TestDemurrageUnit):
expected_balance = int(mint_amount - ((self.tax_level / 1000000) * mint_amount)) 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]) o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
balance = c.parse_balance(r) balance = c.parse_balance(r)
@ -175,9 +183,6 @@ class TestRedistribution(TestDemurrageUnit):
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0]) o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
demurrage = c.parse_to_redistribution_item(r) 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)) logg.debug('\nrediistribution {}\ndemurrage {}\nsupply {}'.format(redistribution, demurrage, supply))
expected_balance = int(supply * (self.tax_level / 1000000)) expected_balance = int(supply * (self.tax_level / 1000000))

View File

@ -20,8 +20,6 @@ contract DemurrageTokenSingleCap {
// Cached demurrage amount, ppm with 38 digit resolution // Cached demurrage amount, ppm with 38 digit resolution
uint128 public demurrageAmount; 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 // Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
uint256 public demurrageTimestamp; uint256 public demurrageTimestamp;
@ -42,8 +40,11 @@ contract DemurrageTokenSingleCap {
// Implements ERC20 // Implements ERC20
uint256 public totalSupply; uint256 public totalSupply;
// Minimum amount of (demurraged) tokens an account must spend to participate in redistribution for a particular period // Last executed period
uint256 public minimumParticipantSpend; uint256 public lastPeriod;
// Last sink redistribution amount
uint256 public totalSink;
// 128 bit resolution of the demurrage divisor // 128 bit resolution of the demurrage divisor
// (this constant x 1000000 is contained within 128 bits) // (this constant x 1000000 is contained within 128 bits)
@ -71,7 +72,7 @@ contract DemurrageTokenSingleCap {
mapping (address => mapping (address => uint256 ) ) allowance; // holder -> spender -> amount (amount is subject to demurrage) mapping (address => mapping (address => uint256 ) ) allowance; // holder -> spender -> amount (amount is subject to demurrage)
// Address to send unallocated redistribution tokens // Address to send unallocated redistribution tokens
address sinkAddress; address public sinkAddress;
// Implements ERC20 // Implements ERC20
event Transfer(address indexed _from, address indexed _to, uint256 _value); event Transfer(address indexed _from, address indexed _to, uint256 _value);
@ -111,17 +112,13 @@ contract DemurrageTokenSingleCap {
demurrageTimestamp = block.timestamp; demurrageTimestamp = block.timestamp;
periodStart = demurrageTimestamp; periodStart = demurrageTimestamp;
periodDuration = _periodMinutes * 60; periodDuration = _periodMinutes * 60;
//demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor demurrageAmount = uint128(nanoDivider) * 100;
//demurrageAmount = 100000000000000000000000000000000000000;
demurrageAmount = 10000000000000000000000000000;
//demurragePeriod = 1;
taxLevel = _taxLevelMinute; // Represents 38 decimal places taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1); bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution); redistributions.push(initialRedistribution);
// Misc settings // Misc settings
sinkAddress = _defaultSinkAddress; sinkAddress = _defaultSinkAddress;
minimumParticipantSpend = 10 ** uint256(_decimals);
} }
@ -153,10 +150,8 @@ contract DemurrageTokenSingleCap {
baseBalance = baseBalanceOf(_account); baseBalance = baseBalanceOf(_account);
//periodCount = actualPeriod() - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp); periodCount = getMinutesDelta(demurrageTimestamp);
//currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount)); currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount));
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000); return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
@ -254,7 +249,6 @@ contract DemurrageTokenSingleCap {
uint256 currentRedistribution; uint256 currentRedistribution;
uint256 grownSupply; uint256 grownSupply;
//grownSupply = growBy(totalSupply, 1);
grownSupply = totalSupply; grownSupply = totalSupply;
currentRedistribution = uint256(redistributions[redistributions.length-1]); currentRedistribution = uint256(redistributions[redistributions.length-1]);
currentRedistribution &= (~maskRedistributionValue); currentRedistribution &= (~maskRedistributionValue);
@ -274,7 +268,7 @@ contract DemurrageTokenSingleCap {
bytes32 lastRedistribution; bytes32 lastRedistribution;
uint256 currentPeriod; uint256 currentPeriod;
lastRedistribution = redistributions[redistributions.length-1]; lastRedistribution = redistributions[lastPeriod];
currentPeriod = this.actualPeriod(); currentPeriod = this.actualPeriod();
if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) { if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
return bytes32(0x00); return bytes32(0x00);
@ -285,8 +279,7 @@ contract DemurrageTokenSingleCap {
function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) { function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
uint256 difference; uint256 difference;
//difference = _supply * (resolutionFactor - _demurrageAmount); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider)); difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000));
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000)); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
return difference / resolutionFactor; return difference / resolutionFactor;
} }
@ -302,9 +295,13 @@ contract DemurrageTokenSingleCap {
// Returns the amount sent to the sink address // Returns the amount sent to the sink address
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) { function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
uint256 unit; uint256 unit;
uint256 baseUnit;
unit = getDistributionFromRedistribution(_redistribution); unit = getDistributionFromRedistribution(_redistribution);
increaseBaseBalance(sinkAddress, toBaseAmount(unit)); baseUnit = toBaseAmount(unit) - totalSink;
increaseBaseBalance(sinkAddress, baseUnit);
lastPeriod += 1;
totalSink += baseUnit;
return unit; return unit;
} }
@ -319,13 +316,9 @@ contract DemurrageTokenSingleCap {
} }
function applyDemurrageLimited(uint256 _rounds) public returns (bool) { function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
//uint128 epochPeriodCount;
uint256 periodCount; uint256 periodCount;
uint256 lastDemurrageAmount; uint256 lastDemurrageAmount;
//epochPeriodCount = actualPeriod();
//periodCount = epochPeriodCount - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp); periodCount = getMinutesDelta(demurrageTimestamp);
if (periodCount == 0) { if (periodCount == 0) {
return false; return false;
@ -423,7 +416,6 @@ contract DemurrageTokenSingleCap {
// Inflates the given amount according to the current demurrage modifier // Inflates the given amount according to the current demurrage modifier
function toBaseAmount(uint256 _value) public view returns (uint256) { function toBaseAmount(uint256 _value) public view returns (uint256) {
//return (_value * resolutionFactor) / demurrageAmount;
return (_value * resolutionFactor) / (demurrageAmount * 10000000000); return (_value * resolutionFactor) / (demurrageAmount * 10000000000);
} }
@ -474,7 +466,6 @@ contract DemurrageTokenSingleCap {
decreaseBaseBalance(_from, _value); decreaseBaseBalance(_from, _value);
increaseBaseBalance(_to, _value); increaseBaseBalance(_to, _value);
//period = actualPeriod();
return true; return true;
} }