13 Commits

Author SHA1 Message Date
nolash
43b3d2b488 Use explicit pre-release signer 2021-08-24 21:49:06 +02:00
nolash
0e1613c5f6 Upgrade deps 2021-07-23 11:22:11 +02:00
nolash
899efb65fc Upgrade deps 2021-07-14 13:17:45 +02:00
nolash
f84edb5f3b Include default config dir in data 2021-07-05 15:45:01 +02:00
nolash
c6b5d9a8e0 Move test base to externally importable path 2021-07-05 10:26:39 +02:00
nolash
abe82949ea Add slow demurrage calc 2021-07-04 14:52:12 +02:00
nolash
a6f53e7278 Correct demurrage emu minutes logline 2021-07-04 14:37:56 +02:00
nolash
98c460dc2f Create demurrage calc from contract 2021-07-04 12:10:01 +02:00
nolash
00bb87e3ec Add python demurrage calculator 2021-07-02 15:29:56 +02:00
nolash
294ded19f5 Move to chainlib-eth 2021-06-28 11:46:05 +02:00
nolash
2c1b7cbb1e Fix result block flag 2021-06-09 16:10:34 +02:00
nolash
d8f9fedecf Update gas budget 2021-06-09 14:54:43 +02:00
nolash
c3a6a692ed Test precision loss of 2 bytes in demurrage store in redistribution data 2021-06-08 17:41:49 +02:00
35 changed files with 368 additions and 208 deletions

4
python/CHANGELOG Normal file
View File

@@ -0,0 +1,4 @@
- 0.0.2-pending
* Move to chainlib-eth
- 0.0.1-unreleased
* Interface for redistributed and non-redistributed, with or without cap

View File

@@ -1 +1 @@
include erc20_demurrage_token/data/*
include erc20_demurrage_token/data/* erc20_demurrage_token/data/config/*.ini *requirements.txt

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,68 @@
# standard imports
import logging
import datetime
import math
# eternal imports
from chainlib.eth.constant import ZERO_ADDRESS
# local imports
from .token import DemurrageToken
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class DemurrageCalculator:
def __init__(self, interest_f_minute):
self.r_min = interest_f_minute
self.r_hour = 1 - ((1 -self.r_min) ** 60)
self.r_day = 1 - ((1 -self.r_hour) ** 24)
#self.r_week = interest_f_day ** 7
logg.info('demurrage calculator set with min {:.32f} hour {:.32f} day {:.32f}'.format(self.r_min, self.r_hour, self.r_day))
def amount_since(self, amount, timestamp):
delta = datetime.datetime.utcnow() - datetime.datetime.fromtimestamp(timestamp)
adjusted_amount = amount * ((1 - self.r_day) ** (delta.days))
logg.debug('adjusted for {} days {} -> {}'.format(delta.days, amount, adjusted_amount))
remainder = delta.seconds
remainder_hours = math.floor(remainder / (60 * 60))
adjusted_delta = adjusted_amount * ((1 - self.r_hour) ** remainder_hours)
adjusted_amount -= (adjusted_amount - adjusted_delta)
logg.debug('adjusted for {} hours {} -> {} delta {}'.format(remainder_hours, amount, adjusted_amount, adjusted_delta))
remainder -= (remainder_hours * (60 * 60))
remainder_minutes = math.floor(remainder / 60)
adjusted_delta = adjusted_amount * ((1 - self.r_min) ** remainder_minutes)
adjusted_amount -= (adjusted_amount - adjusted_delta)
logg.debug('adjusted for {} minutes {} -> {} delta {}'.format(remainder_minutes, amount, adjusted_amount, adjusted_delta))
return adjusted_amount
def amount_since_slow(self, amount, timestamp):
delta = datetime.datetime.utcnow() - datetime.datetime.fromtimestamp(timestamp)
remainder_minutes = math.floor(delta.total_seconds() / 60)
adjusted_amount = amount * ((1 - self.r_min) ** remainder_minutes)
logg.debug('adjusted for {} minutes {} -> {} delta {}'.format(remainder_minutes, amount, adjusted_amount, amount - adjusted_amount))
return adjusted_amount
@staticmethod
def from_contract(rpc, chain_spec, contract_address, sender_address=ZERO_ADDRESS):
c = DemurrageToken(chain_spec)
o = c.tax_level(contract_address, sender_address=sender_address)
r = rpc.do(o)
taxlevel_i = c.parse_tax_level(r)
o = c.resolution_factor(contract_address, sender_address=sender_address)
r = rpc.do(o)
divider = c.parse_resolution_factor(r)
logg.debug('taxlevel {} f {}'.format(taxlevel_i, divider))
taxlevel_f = taxlevel_i / divider
return DemurrageCalculator(taxlevel_f)

View File

@@ -28,8 +28,10 @@ from chainlib.eth.gas import (
from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import receipt
from chainlib.eth.constant import ZERO_ADDRESS
import chainlib.eth.cli
# local imports
import erc20_demurrage_token
from erc20_demurrage_token import (
DemurrageToken,
DemurrageTokenSettings,
@@ -41,56 +43,37 @@ logg = logging.getLogger()
script_dir = os.path.dirname(__file__)
data_dir = os.path.join(script_dir, '..', 'data')
default_config_dir = os.environ.get('CONFINI_DIR', '/usr/local/share/sarafu-token')
config_dir = os.path.join(data_dir, 'config')
argparser = argparse.ArgumentParser()
argparser.add_argument('-c', '--config', dest='c', type=str, default=default_config_dir, help='configuration directory')
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('-i', '--chain-spec', dest='i', type=str, default='evm: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('-v', action='store_true', help='Be verbose')
argparser.add_argument('-vv', action='store_true', help='Be more verbose')
argparser.add_argument('-d', action='store_true', help='Dump RPC calls to terminal and do not send')
argparser.add_argument('--name', type=str, help='Token name')
argparser.add_argument('--decimals', default=6, type=int, help='Token decimals')
argparser.add_argument('--gas-price', type=int, dest='gas_price', help='Override gas price')
argparser.add_argument('--nonce', type=int, help='Override transaction nonce')
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', 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('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
argparser.add_argument('--symbol', type=str, help='Token symbol')
argparser.add_argument('--multi', action='store_true', help='automatic redistribution')
argparser.add_argument('--demurrage-level', dest='demurrage_level', type=int, help='demurrage level, ppm per minute')
args = argparser.parse_args()
if args.vv:
logg.setLevel(logging.DEBUG)
elif args.v:
logg.setLevel(logging.INFO)
arg_flags = chainlib.eth.cli.argflag_std_write
block_last = args.w
block_all = args.ww
# process config
config = confini.Config(args.c)
config.process()
args_override = {
'TOKEN_REDISTRIBUTION_PERIOD': getattr(args, 'redistribution_period'),
'TOKEN_DEMURRAGE_LEVEL': getattr(args, 'demurrage_level'),
'TOKEN_SUPPLY_LIMIT': getattr(args, 'supply_limit'),
'TOKEN_SYMBOL': getattr(args, 'symbol'),
'TOKEN_NAME': getattr(args, 'name'),
'TOKEN_DECIMALS': getattr(args, 'decimals'),
'TOKEN_SINK_ADDRESS': getattr(args, 'sink_address'),
'SESSION_CHAIN_SPEC': getattr(args, 'i'),
'ETH_PROVIDER': getattr(args, 'p'),
extra_args = {
'redistribution_period': 'TOKEN_REDISTRIBUTION_PERIOD',
'demurrage_level': 'TOKEN_DEMURRAGE_LEVEL',
'supply_limit': 'TOKEN_SUPPLY_LIMIT',
'token_name': 'TOKEN_NAME',
'token_symbol': 'TOKEN_SYMBOL',
'token_decimals': 'TOKEN_DECIMALS',
'sink_address': 'TOKEN_SINK_ADDRESS',
'multi': None,
}
if config.get('TOKEN_NAME') == None:
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_fee_limit=DemurrageToken.gas(), base_config_dir=config_dir)
if not bool(config.get('TOKEN_NAME')):
logg.info('token name not set, using symbol {} as name'.format(config.get('TOKEN_SYMBOL')))
config.add(config.get('TOKEN_SYMBOL'), 'TOKEN_NAME', True)
config.dict_override(args_override, 'cli args')
if config.get('TOKEN_SUPPLY_LIMIT') == None:
config.add(0, 'TOKEN_SUPPLY_LIMIT', True)
@@ -99,44 +82,22 @@ if config.get('TOKEN_REDISTRIBUTION_PERIOD') == None:
config.add(10800, 'TOKEN_REDISTRIBUTION_PERIOD', True)
logg.debug('config loaded:\n{}'.format(config))
passphrase_env = 'ETH_PASSPHRASE'
if args.env_prefix != None:
passphrase_env = args.env_prefix + '_' + passphrase_env
passphrase = os.environ.get(passphrase_env)
if passphrase == None:
logg.warning('no passphrase given')
passphrase=''
wallet = chainlib.eth.cli.Wallet()
wallet.from_config(config)
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, password=passphrase)
logg.debug('now have key for signer address {}'.format(signer_address))
signer = EIP155Signer(keystore)
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
conn = rpc.connect_by_config(config)
chain_spec = ChainSpec.from_chain_str(args.i)
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
rpc = EthHTTPConnection(args.p)
nonce_oracle = None
if args.nonce != None:
nonce_oracle = OverrideNonceOracle(signer_address, args.nonce)
else:
nonce_oracle = RPCNonceOracle(signer_address, rpc)
gas_oracle = None
if args.gas_price !=None:
gas_oracle = OverrideGasOracle(price=args.gas_price, conn=rpc, code_callback=DemurrageToken.gas)
else:
gas_oracle = RPCGasOracle(rpc, code_callback=DemurrageToken.gas)
dummy = args.d
token_name = args.name
if token_name == None:
token_name = args.symbol
def main():
signer = rpc.get_signer()
signer_address = rpc.get_sender_address()
gas_oracle = rpc.get_gas_oracle()
nonce_oracle = rpc.get_nonce_oracle()
c = DemurrageToken(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
settings = DemurrageTokenSettings()
settings.name = config.get('TOKEN_NAME')
@@ -149,16 +110,13 @@ def main():
(tx_hash_hex, o) = c.constructor(
signer_address,
settings,
redistribute=settings.period_minutes > 0,
redistribute=config.true('_MULTI'),
cap=int(config.get('TOKEN_SUPPLY_LIMIT')),
)
if dummy:
print(tx_hash_hex)
print(o)
else:
rpc.do(o)
if block_last:
r = rpc.wait(tx_hash_hex)
if config.get('_RPC_SEND'):
conn.do(o)
if 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)
@@ -169,6 +127,9 @@ def main():
else:
print(tx_hash_hex)
else:
print(o)
if __name__ == '__main__':
main()

View File

@@ -200,7 +200,7 @@ class DemurrageTokenSimulation:
else:
o = self.caller_contract.balance_of(self.address, holder, sender_address=self.caller_address)
r = self.rpc.do(o)
return self.caller_contract.parse_balance_of(r)
return self.caller_contract.parse_balance(r)
def __next_block(self):

View File

@@ -14,7 +14,7 @@ from chainlib.eth.contract import (
abi_decode_single,
)
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.jsonrpc import jsonrpc_template
from chainlib.jsonrpc import JSONRPCRequest
from eth_erc20 import ERC20
from hexathon import (
add_0x,
@@ -70,7 +70,7 @@ class DemurrageToken(ERC20):
@staticmethod
def gas(code=None):
return 3500000
return 4000000
@staticmethod
@@ -146,8 +146,9 @@ class DemurrageToken(ERC20):
return tx
def to_base_amount(self, contract_address, value, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def to_base_amount(self, contract_address, value, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toBaseAmount')
@@ -158,11 +159,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def remainder(self, contract_address, parts, whole, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def remainder(self, contract_address, parts, whole, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('remainder')
@@ -175,11 +178,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def redistributions(self, contract_address, idx, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def redistributions(self, contract_address, idx, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('redistributions')
@@ -190,11 +195,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def account_period(self, contract_address, address, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def account_period(self, contract_address, address, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('accountPeriod')
@@ -205,11 +212,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def to_redistribution(self, contract_address, participants, demurrage_modifier_ppm, value, period, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def to_redistribution(self, contract_address, participants, demurrage_modifier_ppm, value, period, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toRedistribution')
@@ -226,12 +235,14 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def to_redistribution_period(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def to_redistribution_period(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toRedistributionPeriod')
@@ -242,11 +253,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def to_redistribution_participants(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def to_redistribution_participants(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toRedistributionParticipants')
@@ -257,11 +270,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def to_redistribution_supply(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def to_redistribution_supply(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toRedistributionSupply')
@@ -272,11 +287,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def to_redistribution_demurrage_modifier(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def to_redistribution_demurrage_modifier(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toRedistributionDemurrageModifier')
@@ -287,11 +304,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def base_balance_of(self, contract_address, address, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def base_balance_of(self, contract_address, address, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('baseBalanceOf')
@@ -302,6 +321,7 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
@@ -323,7 +343,15 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx
def tax_level(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('taxLevel', contract_address, sender_address=sender_address)
def resolution_factor(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('resolutionFactor', contract_address, sender_address=sender_address)
def actual_period(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('actualPeriod', contract_address, sender_address=sender_address)
@@ -345,8 +373,9 @@ class DemurrageToken(ERC20):
return self.call_noarg('supplyCap', contract_address, sender_address=sender_address)
def grow_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def grow_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('growBy')
@@ -359,11 +388,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def decay_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def decay_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('decayBy')
@@ -376,11 +407,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def get_distribution(self, contract_address, supply, demurrage_amount, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def get_distribution(self, contract_address, supply, demurrage_amount, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('getDistribution')
@@ -393,11 +426,13 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
def get_distribution_from_redistribution(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
def get_distribution_from_redistribution(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('getDistributionFromRedistribution')
@@ -408,6 +443,7 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
o = j.finalize(o)
return o
@@ -479,3 +515,13 @@ class DemurrageToken(ERC20):
@classmethod
def parse_get_distribution(self, v):
return abi_decode_single(ABIContractType.UINT256, v)
@classmethod
def parse_tax_level(self, v):
return abi_decode_single(ABIContractType.UINT256, v)
@classmethod
def parse_resolution_factor(self, v):
return abi_decode_single(ABIContractType.UINT256, v)

View File

@@ -0,0 +1 @@
from .base import *

View File

@@ -12,6 +12,7 @@ from chainlib.eth.block import (
block_by_number,
)
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.constant import ZERO_ADDRESS
# local imports
from erc20_demurrage_token import (
@@ -29,64 +30,93 @@ TAX_LEVEL = int(10000 * 2) # 2%
PERIOD = 10
class TestDemurrage(EthTesterCase):
def setUp(self):
super(TestDemurrage, self).setUp()
class TestTokenDeploy:
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
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
self.settings = DemurrageTokenSettings()
self.settings.name = 'Foo Token'
self.settings.symbol = 'FOO'
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.sink_address = self.accounts[9]
self.settings.sink_address = sink_address
self.sink_address = self.settings.sink_address
o = block_latest()
self.start_block = self.rpc.do(o)
self.start_block = rpc.do(o)
o = block_by_number(self.start_block, include_tx=False)
r = self.rpc.do(o)
r = rpc.do(o)
try:
self.start_time = int(r['timestamp'], 16)
except TypeError:
self.start_time = int(r['timestamp'])
self.default_supply = 10 ** 12
self.default_supply = supply
self.default_supply_cap = int(self.default_supply * 10)
def deploy(self, interface, mode):
def deploy(self, rpc, deployer_address, interface, mode, supply_cap=10**12):
tx_hash = None
o = None
logg.debug('mode {} {}'.format(mode, self.settings))
self.mode = mode
if mode == 'MultiNocap':
(tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=True, cap=0)
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=True, cap=0)
elif mode == 'SingleNocap':
(tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=0)
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=0)
elif mode == 'MultiCap':
(tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=True, cap=self.default_supply_cap)
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=True, cap=supply_cap)
elif mode == 'SingleCap':
(tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=self.default_supply_cap)
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=supply_cap)
else:
raise ValueError('Invalid mode "{}", valid are {}'.format(self.mode, DemurrageToken.valid_modes))
raise ValueError('Invalid mode "{}", valid are {}'.format(mode, DemurrageToken.valid_modes))
r = self.rpc.do(o)
r = rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
r = rpc.do(o)
assert r['status'] == 1
self.start_block = r['block_number']
self.address = r['contract_address']
o = block_by_number(r['block_number'])
r = self.rpc.do(o)
r = rpc.do(o)
self.start_time = r['timestamp']
return self.address
class TestDemurrage(EthTesterCase):
def setUp(self):
super(TestDemurrage, self).setUp()
# token_deploy = TestTokenDeploy()
# self.settings = token_deploy.settings
# self.sink_address = token_deploy.sink_address
# self.start_block = token_deploy.start_block
# self.start_time = token_deploy.start_time
# self.default_supply = self.default_supply
# self.default_supply_cap = self.default_supply_cap
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
self.address = None
self.start_time = None
def deploy(self, interface, mode):
self.address = self.deployer.deploy(self.rpc, self.accounts[0], interface, mode, supply_cap=self.default_supply_cap)
self.start_block = self.deployer.start_block
self.start_time = self.deployer.start_time
self.tax_level = self.deployer.tax_level
self.period_seconds = self.deployer.period_seconds
self.sink_address = self.deployer.sink_address
logg.debug('contract address {} start block {} start time {}'.format(self.address, self.start_block, self.start_time))

View File

@@ -17,9 +17,10 @@ settings.symbol = 'SIM'
settings.decimals = 6
settings.demurrage_level = int(decay_per_minute*(10**38))
#settings.period_minutes = 1 # 1 week in minutes
settings.period_minutes = 10
settings.period_minutes = 60*24*7
chain = 'evm:foochain:42'
cap = (10 ** 6) * (10 ** 12)
#cap = 0
# instantiate simulation
sim = DemurrageTokenSimulation(chain, settings, redistribute=False, cap=cap, actors=10)

View File

@@ -1,3 +1,3 @@
chainlib~=0.0.3rc3
eth-erc20~=0.0.9a4
crypto-dev-signer~=0.4.14b3
chainlib>=0.0.9a3,<=0.1.0
eth-erc20>=0.1.2a1,<0.2.0
crypto-dev-signer>=0.4.15a1,<=0.4.15

View File

@@ -1,5 +1,6 @@
#!/bin/bash
set -x
set -e
export PYTHONPATH=.
@@ -7,10 +8,16 @@ export PYTHONPATH=.
#modes=(MultiNocap MultiCap SingleCap SingleNocap)
modes=(SingleCap SingleNocap) # other contracts need to be updted
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_basic.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_growth.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_amounts.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_single.py
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
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py
done
modes=(MultiCap SingleCap)
@@ -18,12 +25,6 @@ for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_cap.py
done
modes=(SingleCap SingleNocap)
for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_single.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py
done
#modes=(MultiCap MultiNocap)
#for m in ${modes[@]}; do
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_remainder.py
@@ -31,3 +32,4 @@ done
#done
set +e
set +x

View File

@@ -1,10 +1,10 @@
[metadata]
name = erc20-demurrage-token
version = 0.0.1b3
version = 0.0.5a2
description = ERC20 token with redistributed continual demurrage
author = Louis Holbrook
author_email = dev@holbrook.no
url = https://gitlab.com/grassrootseconomics/sarafu-token
url = https://gitlab.com/ccicnet/erc20-demurrage-token
keywords =
ethereum
blockchain

View File

@@ -1,3 +1,2 @@
#web3==5.12.2
eth_tester==0.5.0b3
py-evm==0.3.0a20

View File

@@ -13,7 +13,7 @@ from chainlib.eth.tx import receipt
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -35,7 +35,7 @@ class TestAmounts(TestDemurrageDefault):
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 = c.parse_balance(r)
self.assertEqual(balance, 817)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1000)
@@ -43,7 +43,7 @@ class TestAmounts(TestDemurrageDefault):
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 = c.parse_balance(r)
self.assert_within_lower(balance, 1817, 750)
self.backend.time_travel(self.start_time + self.period_seconds * 2)
@@ -53,7 +53,7 @@ class TestAmounts(TestDemurrageDefault):
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 = c.parse_balance(r)
expected_balance = ((1 - self.tax_level / 1000000) ** 10) * 1000
expected_balance += ((1 - self.tax_level / 1000000) ** 20) * 1000
@@ -73,7 +73,7 @@ class TestAmounts(TestDemurrageDefault):
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 = c.parse_balance(r)
self.assertEqual(balance, 1634)
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
@@ -83,12 +83,12 @@ class TestAmounts(TestDemurrageDefault):
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 = c.parse_balance(r)
self.assertEqual(balance, 1134)
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)
balance = c.parse_balance(r)
self.assert_within_lower(balance, 500, 2000)
@@ -115,7 +115,7 @@ class TestAmounts(TestDemurrageDefault):
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 = c.parse_balance(r)
self.assertEqual(balance, case[1])

View File

@@ -18,7 +18,7 @@ from chainlib.eth.block import (
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()

View File

@@ -18,7 +18,7 @@ from hexathon import (
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageCap
from erc20_demurrage_token.unittest.base import TestDemurrageCap
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()

View File

@@ -0,0 +1,41 @@
# standard imports
import datetime
import unittest
# external imports
from chainlib.eth.nonce import RPCNonceOracle
# local imports
from erc20_demurrage_token import DemurrageToken
from erc20_demurrage_token.demurrage import DemurrageCalculator
# test imports
from erc20_demurrage_token.unittest.base import TestDemurrage
class TestEmulate(TestDemurrage):
def test_amount_since(self):
d = datetime.datetime.utcnow() - datetime.timedelta(seconds=29, hours=5, minutes=3, days=4)
c = DemurrageCalculator(0.00000050105908373373)
a = c.amount_since(100, d.timestamp())
self.assert_within_lower(a, 99.69667, 0.1)
def test_amount_since_slow(self):
d = datetime.datetime.utcnow() - datetime.timedelta(seconds=29, hours=5, minutes=3, days=4)
c = DemurrageCalculator(0.00000050105908373373)
a = c.amount_since_slow(100, d.timestamp())
self.assert_within_lower(a, 99.69667, 0.1)
def test_from_contract(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
self.deploy(c, 'SingleNocap')
dc = DemurrageCalculator.from_contract(self.rpc, self.chain_spec, self.address, sender_address=self.accounts[0])
self.assertEqual(dc.r_min, 0.02)
if __name__ == '__main__':
unittest.main()

View File

@@ -18,7 +18,7 @@ from chainlib.eth.block import (
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()

View File

@@ -13,7 +13,7 @@ from chainlib.eth.tx import receipt
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -70,10 +70,10 @@ class TestPeriod(TestDemurrageDefault):
# allow test code float rounding error to billionth
modifier = (1 - (self.tax_level / 1000000)) ** (self.period_seconds / 60)
modifier *= 10 ** 9
modifier = int(modifier) * (10 ** (38 - 9))
modifier = int(modifier) * (10 ** (28 - 9))
period /= (10 ** (38 - 9))
period = int(period) * (10 ** (38 - 9))
period /= (10 ** (28 - 9))
period = int(period) * (10 ** (28 - 9))
self.assertEqual(modifier, period)
self.backend.time_travel(self.start_time + self.period_seconds * 2)
@@ -96,10 +96,10 @@ class TestPeriod(TestDemurrageDefault):
# allow test code float rounding error to billionth
modifier = (1 - (self.tax_level / 1000000)) ** ((self.period_seconds * 2) / 60)
modifier *= 10 ** 9
modifier = int(modifier) * (10 ** (38 - 9))
modifier = int(modifier) * (10 ** (28 - 9))
period /= (10 ** (38 - 9))
period = int(period) * (10 ** (38 - 9))
period /= (10 ** (28 - 9))
period = int(period) * (10 ** (28 - 9))
self.assertEqual(modifier, period)

View File

@@ -22,7 +22,7 @@ from hexathon import (
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()

View File

@@ -21,7 +21,7 @@ from hexathon import (
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageUnit
from erc20_demurrage_token.unittest.base import TestDemurrageUnit
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -36,21 +36,23 @@ 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 / 1000000)) * (10**38)
#demurrage = (1 - (self.tax_level / 1000000)) * (10**38)
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
supply = self.default_supply
o = c.get_distribution(self.address, supply, demurrage, sender_address=self.accounts[0])
r = self.rpc.do(o)
distribution = c.parse_get_distribution(r)
expected_distribution = self.default_supply * (self.tax_level / 1000000)
self.assertEqual(distribution, expected_distribution)
self.assert_within_lower(distribution, expected_distribution, 1000)
def test_distribution_from_redistribution(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**38)
demurrage = (1 - (self.tax_level / 1000000)) * (10**28)
supply = self.default_supply
o = c.to_redistribution(self.address, 0, demurrage, supply, 1, sender_address=self.accounts[0])
@@ -60,8 +62,7 @@ class TestRedistribution(TestDemurrageUnit):
r = self.rpc.do(o)
distribution = c.parse_get_distribution(r)
expected_distribution = self.default_supply * (self.tax_level / 1000000)
self.assertEqual(distribution, expected_distribution)
self.assert_within_lower(distribution, expected_distribution, 1000)
def test_single_step(self):
@@ -82,7 +83,7 @@ class TestRedistribution(TestDemurrageUnit):
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 = c.parse_balance(r)
self.assertEqual(balance, expected_balance)
@@ -107,7 +108,7 @@ class TestRedistribution(TestDemurrageUnit):
for i in range(3):
o = c.balance_of(self.address, self.accounts[i+1], sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
balance = c.parse_balance(r)
self.assertEqual(balance, expected_balance)
@@ -146,7 +147,7 @@ class TestRedistribution(TestDemurrageUnit):
expected_balance = mint_amount - demurrage_amount
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)
balance = c.parse_balance(r)
self.assertEqual(balance, expected_balance)
half_demurrage_amount = int((self.tax_level / 1000000) * half_mint_amount)
@@ -154,12 +155,12 @@ class TestRedistribution(TestDemurrageUnit):
expected_balance = half_mint_amount - half_demurrage_amount
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 = c.parse_balance(r)
self.assertEqual(balance, expected_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)
balance = c.parse_balance(r)
self.assertEqual(balance, expected_balance)
o = c.total_supply(self.address, sender_address=self.accounts[0])
@@ -184,7 +185,7 @@ class TestRedistribution(TestDemurrageUnit):
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
balance = c.parse_balance(r)
self.assert_within_lower(balance, expected_balance, 1000)

View File

@@ -16,7 +16,7 @@ import eth_tester
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageDefault
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()

View File

@@ -18,7 +18,7 @@ from hexathon import (
from erc20_demurrage_token import DemurrageToken
# test imports
from tests.base import TestDemurrageSingle
from erc20_demurrage_token.unittest.base import TestDemurrageSingle
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -67,18 +67,18 @@ class TestRedistributionSingle(TestDemurrageSingle):
tax_modifier = (1 - (self.tax_level / 1000000)) ** 10
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 = c.parse_balance(r)
self.assertEqual(balance, int(mint_amount * tax_modifier))
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)
balance = c.parse_balance(r)
base_amount = mint_amount - int(mint_amount * 0.1)
self.assertEqual(balance, int(base_amount * tax_modifier)) #(base_amount - (base_amount * (self.tax_level / 1000000))))
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)
balance = c.parse_balance(r)
base_amount = mint_amount - int(mint_amount * 0.2)
self.assertEqual(balance, int(base_amount * tax_modifier)) #(base_amount - (base_amount * (self.tax_level / 1000000))))
@@ -88,7 +88,7 @@ class TestRedistributionSingle(TestDemurrageSingle):
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
balance = c.parse_balance(r)
expected_balance = new_supply - (new_supply * tax_modifier)
self.assert_within_lower(balance, expected_balance, 1)

View File

@@ -61,6 +61,9 @@ contract DemurrageTokenMultiCap {
// (this constant x 1000000 is contained within 128 bits)
uint256 constant ppmDivider = 100000000000000000000000000000000;
// demurrage decimal width; 38 places
uint256 public immutable resolutionFactor = ppmDivider * 1000000;
// Timestamp of start of periods (time which contract constructor was called)
uint256 public immutable periodStart;

View File

@@ -56,6 +56,9 @@ contract DemurrageTokenMultiNocap {
// (this constant x 1000000 is contained within 128 bits)
uint256 constant ppmDivider = 100000000000000000000000000000000;
// demurrage decimal width; 38 places
uint256 public immutable resolutionFactor = ppmDivider * 1000000;
// Timestamp of start of periods (time which contract constructor was called)
uint256 public immutable periodStart;

View File

@@ -12,7 +12,7 @@ contract DemurrageTokenSingleCap {
uint8 constant shiftRedistributionValue = 32;
uint256 constant maskRedistributionValue = 0x00000000000000000000000000000000000000ffffffffffffffffff00000000; // ((1 << 72) - 1) << 32
uint8 constant shiftRedistributionDemurrage = 104;
uint256 constant maskRedistributionDemurrage = 0x000000ffffffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140
uint256 constant maskRedistributionDemurrage = 0x0000000000ffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140
// Account balances
mapping (address => uint256) account;
@@ -56,7 +56,7 @@ contract DemurrageTokenSingleCap {
uint256 constant growthResolutionFactor = 1000000000000;
// demurrage decimal width; 38 places
uint256 immutable resolutionFactor = nanoDivider * growthResolutionFactor;
uint256 public immutable resolutionFactor = nanoDivider * growthResolutionFactor;
// Timestamp of start of periods (time which contract constructor was called)
uint256 public immutable periodStart;
@@ -115,7 +115,8 @@ contract DemurrageTokenSingleCap {
periodStart = demurrageTimestamp;
periodDuration = _periodMinutes * 60;
//demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor
demurrageAmount = 100000000000000000000000000000000000000;
//demurrageAmount = 100000000000000000000000000000000000000;
demurrageAmount = 10000000000000000000000000000;
//demurragePeriod = 1;
taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
@@ -152,7 +153,7 @@ contract DemurrageTokenSingleCap {
//periodCount = actualPeriod() - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp);
currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount));
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
}
@@ -281,7 +282,7 @@ contract DemurrageTokenSingleCap {
function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
uint256 difference;
difference = _supply * (resolutionFactor - _demurrageAmount); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000)); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
return difference / resolutionFactor;
}
@@ -407,7 +408,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);
}
// Implements ERC20, triggers tax and/or redistribution

View File

@@ -12,11 +12,7 @@ contract DemurrageTokenSingleCap {
uint8 constant shiftRedistributionValue = 32;
uint256 constant maskRedistributionValue = 0x00000000000000000000000000000000000000ffffffffffffffffff00000000; // ((1 << 72) - 1) << 32
uint8 constant shiftRedistributionDemurrage = 104;
uint256 constant maskRedistributionDemurrage = 0x000000ffffffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140
uint8 constant shiftRedistributionIsUsed = 255;
uint256 constant maskRedistributionIsUsed = 0x4000000000000000000000000000000000000000000000000000000000000000; // 1 << 255
uint256 constant maskRedistributionDemurrage = 0x0000000000ffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140
// Account balances
mapping (address => uint256) account;
@@ -57,7 +53,7 @@ contract DemurrageTokenSingleCap {
uint256 constant growthResolutionFactor = 1000000000000;
// demurrage decimal width; 38 places
uint256 immutable resolutionFactor = nanoDivider * growthResolutionFactor;
uint256 public immutable resolutionFactor = nanoDivider * growthResolutionFactor;
// Timestamp of start of periods (time which contract constructor was called)
uint256 public immutable periodStart;
@@ -116,7 +112,8 @@ contract DemurrageTokenSingleCap {
periodStart = demurrageTimestamp;
periodDuration = _periodMinutes * 60;
//demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor
demurrageAmount = 100000000000000000000000000000000000000;
//demurrageAmount = 100000000000000000000000000000000000000;
demurrageAmount = 10000000000000000000000000000;
//demurragePeriod = 1;
taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
@@ -152,7 +149,8 @@ contract DemurrageTokenSingleCap {
//periodCount = actualPeriod() - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp);
currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
//currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount));
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
}
@@ -406,7 +404,8 @@ 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;
return (_value * resolutionFactor) / (demurrageAmount * 10000000000);
}
// Implements ERC20, triggers tax and/or redistribution