Compare commits
21 Commits
0.0.2-dev
...
lash/chain
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7af21e233
|
||
|
|
276b346e52
|
||
|
|
6dc843fb5d
|
||
|
|
a04c826ba7
|
||
|
|
04f50cdede
|
||
| 21d65522a8 | |||
|
130b5ea587
|
|||
|
e486e9f31a
|
|||
|
959b018247
|
|||
|
6ecacd60d4
|
|||
|
c40157318f
|
|||
|
|
025ef614a5
|
||
|
|
43b3d2b488
|
||
|
|
0e1613c5f6
|
||
|
|
899efb65fc
|
||
|
|
f84edb5f3b
|
||
|
|
c6b5d9a8e0
|
||
|
|
abe82949ea
|
||
|
|
a6f53e7278
|
||
|
|
98c460dc2f
|
||
|
|
00bb87e3ec
|
@@ -1,4 +1,7 @@
|
|||||||
- 0.0.2-pending
|
- 0.0.9
|
||||||
|
* Fix wrong redistribution calculation in single nocap
|
||||||
|
[...]
|
||||||
|
- 0.0.2
|
||||||
* Move to chainlib-eth
|
* Move to chainlib-eth
|
||||||
- 0.0.1-unreleased
|
- 0.0.1-unreleased
|
||||||
* Interface for redistributed and non-redistributed, with or without cap
|
* Interface for redistributed and non-redistributed, with or without cap
|
||||||
|
|||||||
@@ -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
68
python/erc20_demurrage_token/demurrage.py
Normal file
68
python/erc20_demurrage_token/demurrage.py
Normal 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)
|
||||||
@@ -14,8 +14,8 @@ import logging
|
|||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
import confini
|
import confini
|
||||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
from funga.eth.signer import EIP155Signer
|
||||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
from funga.eth.keystore.dict import DictKeystore
|
||||||
from chainlib.chain import ChainSpec
|
from chainlib.chain import ChainSpec
|
||||||
from chainlib.eth.nonce import (
|
from chainlib.eth.nonce import (
|
||||||
RPCNonceOracle,
|
RPCNonceOracle,
|
||||||
@@ -28,8 +28,10 @@ from chainlib.eth.gas import (
|
|||||||
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
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
|
import erc20_demurrage_token
|
||||||
from erc20_demurrage_token import (
|
from erc20_demurrage_token import (
|
||||||
DemurrageToken,
|
DemurrageToken,
|
||||||
DemurrageTokenSettings,
|
DemurrageTokenSettings,
|
||||||
@@ -41,56 +43,37 @@ logg = logging.getLogger()
|
|||||||
script_dir = os.path.dirname(__file__)
|
script_dir = os.path.dirname(__file__)
|
||||||
data_dir = os.path.join(script_dir, '..', 'data')
|
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()
|
arg_flags = chainlib.eth.cli.argflag_std_write
|
||||||
argparser.add_argument('-c', '--config', dest='c', type=str, default=default_config_dir, help='configuration directory')
|
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||||
argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='Web3 provider url (http only)')
|
argparser.add_argument('--name', dest='token_name', type=str, help='Token name')
|
||||||
argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed')
|
argparser.add_argument('--symbol', dest='token_symbol', required=True, type=str, help='Token symbol')
|
||||||
argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed')
|
argparser.add_argument('--decimals', dest='token_decimals', default=18, type=int, help='Token decimals')
|
||||||
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')
|
|
||||||
argparser.add_argument('--sink-address', dest='sink_address', default=ZERO_ADDRESS, type=str, help='demurrage level,ppm per minute')
|
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('--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('--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('--multi', action='store_true', help='automatic redistribution')
|
||||||
argparser.add_argument('--symbol', type=str, help='Token symbol')
|
|
||||||
argparser.add_argument('--demurrage-level', dest='demurrage_level', type=int, help='demurrage level, ppm per minute')
|
argparser.add_argument('--demurrage-level', dest='demurrage_level', type=int, help='demurrage level, ppm per minute')
|
||||||
args = argparser.parse_args()
|
args = argparser.parse_args()
|
||||||
|
|
||||||
if args.vv:
|
arg_flags = chainlib.eth.cli.argflag_std_write
|
||||||
logg.setLevel(logging.DEBUG)
|
|
||||||
elif args.v:
|
|
||||||
logg.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
block_all = args.ww
|
extra_args = {
|
||||||
block_last = args.w or block_all
|
'redistribution_period': 'TOKEN_REDISTRIBUTION_PERIOD',
|
||||||
|
'demurrage_level': 'TOKEN_DEMURRAGE_LEVEL',
|
||||||
# process config
|
'supply_limit': 'TOKEN_SUPPLY_LIMIT',
|
||||||
config = confini.Config(args.c)
|
'token_name': 'TOKEN_NAME',
|
||||||
config.process()
|
'token_symbol': 'TOKEN_SYMBOL',
|
||||||
args_override = {
|
'token_decimals': 'TOKEN_DECIMALS',
|
||||||
'TOKEN_REDISTRIBUTION_PERIOD': getattr(args, 'redistribution_period'),
|
'sink_address': 'TOKEN_SINK_ADDRESS',
|
||||||
'TOKEN_DEMURRAGE_LEVEL': getattr(args, 'demurrage_level'),
|
'multi': None,
|
||||||
'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'),
|
|
||||||
}
|
}
|
||||||
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')))
|
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.add(config.get('TOKEN_SYMBOL'), 'TOKEN_NAME', True)
|
||||||
config.dict_override(args_override, 'cli args')
|
|
||||||
|
|
||||||
if config.get('TOKEN_SUPPLY_LIMIT') == None:
|
if config.get('TOKEN_SUPPLY_LIMIT') == None:
|
||||||
config.add(0, 'TOKEN_SUPPLY_LIMIT', True)
|
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)
|
config.add(10800, 'TOKEN_REDISTRIBUTION_PERIOD', True)
|
||||||
logg.debug('config loaded:\n{}'.format(config))
|
logg.debug('config loaded:\n{}'.format(config))
|
||||||
|
|
||||||
passphrase_env = 'ETH_PASSPHRASE'
|
wallet = chainlib.eth.cli.Wallet()
|
||||||
if args.env_prefix != None:
|
wallet.from_config(config)
|
||||||
passphrase_env = args.env_prefix + '_' + passphrase_env
|
|
||||||
passphrase = os.environ.get(passphrase_env)
|
|
||||||
if passphrase == None:
|
|
||||||
logg.warning('no passphrase given')
|
|
||||||
passphrase=''
|
|
||||||
|
|
||||||
signer_address = None
|
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||||
keystore = DictKeystore()
|
conn = rpc.connect_by_config(config)
|
||||||
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)
|
|
||||||
|
|
||||||
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():
|
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)
|
c = DemurrageToken(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
|
||||||
settings = DemurrageTokenSettings()
|
settings = DemurrageTokenSettings()
|
||||||
settings.name = config.get('TOKEN_NAME')
|
settings.name = config.get('TOKEN_NAME')
|
||||||
@@ -149,16 +110,13 @@ def main():
|
|||||||
(tx_hash_hex, o) = c.constructor(
|
(tx_hash_hex, o) = c.constructor(
|
||||||
signer_address,
|
signer_address,
|
||||||
settings,
|
settings,
|
||||||
redistribute=settings.period_minutes > 0,
|
redistribute=config.true('_MULTI'),
|
||||||
cap=int(config.get('TOKEN_SUPPLY_LIMIT')),
|
cap=int(config.get('TOKEN_SUPPLY_LIMIT')),
|
||||||
)
|
)
|
||||||
if dummy:
|
if config.get('_RPC_SEND'):
|
||||||
print(tx_hash_hex)
|
conn.do(o)
|
||||||
print(o)
|
if config.get('_WAIT'):
|
||||||
else:
|
r = conn.wait(tx_hash_hex)
|
||||||
rpc.do(o)
|
|
||||||
if block_last:
|
|
||||||
r = rpc.wait(tx_hash_hex)
|
|
||||||
if r['status'] == 0:
|
if r['status'] == 0:
|
||||||
sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you')
|
sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -169,6 +127,9 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print(tx_hash_hex)
|
print(tx_hash_hex)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(o)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ from chainlib.eth.block import (
|
|||||||
block_by_number,
|
block_by_number,
|
||||||
block_by_hash,
|
block_by_hash,
|
||||||
)
|
)
|
||||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
from funga.eth.keystore.dict import DictKeystore
|
||||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
from funga.eth.signer import EIP155Signer
|
||||||
from hexathon import (
|
from hexathon import (
|
||||||
strip_0x,
|
strip_0x,
|
||||||
add_0x,
|
add_0x,
|
||||||
|
|||||||
@@ -325,8 +325,19 @@ class DemurrageToken(ERC20):
|
|||||||
return o
|
return o
|
||||||
|
|
||||||
|
|
||||||
def apply_demurrage(self, contract_address, sender_address):
|
def apply_demurrage(self, contract_address, sender_address, limit=0, tx_format=TxFormat.JSONRPC):
|
||||||
return self.transact_noarg('applyDemurrage', contract_address, sender_address)
|
if limit == 0:
|
||||||
|
return self.transact_noarg('applyDemurrage', contract_address, sender_address)
|
||||||
|
|
||||||
|
enc = ABIContractEncoder()
|
||||||
|
enc.method('applyDemurrageLimited')
|
||||||
|
enc.typ(ABIContractType.UINT256)
|
||||||
|
enc.uint256(limit)
|
||||||
|
data = enc.get()
|
||||||
|
tx = self.template(sender_address, contract_address, use_nonce=True)
|
||||||
|
tx = self.set_code(tx, data)
|
||||||
|
tx = self.finalize(tx, tx_format)
|
||||||
|
return tx
|
||||||
|
|
||||||
|
|
||||||
def change_period(self, contract_address, sender_address):
|
def change_period(self, contract_address, sender_address):
|
||||||
@@ -343,7 +354,15 @@ class DemurrageToken(ERC20):
|
|||||||
tx = self.set_code(tx, data)
|
tx = self.set_code(tx, data)
|
||||||
tx = self.finalize(tx, tx_format)
|
tx = self.finalize(tx, tx_format)
|
||||||
return tx
|
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):
|
def actual_period(self, contract_address, sender_address=ZERO_ADDRESS):
|
||||||
return self.call_noarg('actualPeriod', contract_address, sender_address=sender_address)
|
return self.call_noarg('actualPeriod', contract_address, sender_address=sender_address)
|
||||||
@@ -507,3 +526,13 @@ class DemurrageToken(ERC20):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def parse_get_distribution(self, v):
|
def parse_get_distribution(self, v):
|
||||||
return abi_decode_single(ABIContractType.UINT256, 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)
|
||||||
|
|||||||
1
python/erc20_demurrage_token/unittest/__init__.py
Normal file
1
python/erc20_demurrage_token/unittest/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .base import *
|
||||||
@@ -12,6 +12,7 @@ from chainlib.eth.block import (
|
|||||||
block_by_number,
|
block_by_number,
|
||||||
)
|
)
|
||||||
from chainlib.eth.nonce import RPCNonceOracle
|
from chainlib.eth.nonce import RPCNonceOracle
|
||||||
|
from chainlib.eth.constant import ZERO_ADDRESS
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from erc20_demurrage_token import (
|
from erc20_demurrage_token import (
|
||||||
@@ -29,64 +30,93 @@ TAX_LEVEL = int(10000 * 2) # 2%
|
|||||||
PERIOD = 10
|
PERIOD = 10
|
||||||
|
|
||||||
|
|
||||||
class TestDemurrage(EthTesterCase):
|
class TestTokenDeploy:
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDemurrage, self).setUp()
|
|
||||||
|
|
||||||
|
def __init__(self, rpc, token_symbol='FOO', token_name='Foo Token', sink_address=ZERO_ADDRESS, supply=10**12):
|
||||||
self.tax_level = TAX_LEVEL
|
self.tax_level = TAX_LEVEL
|
||||||
self.period_seconds = PERIOD * 60
|
self.period_seconds = PERIOD * 60
|
||||||
|
|
||||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
|
||||||
self.settings = DemurrageTokenSettings()
|
self.settings = DemurrageTokenSettings()
|
||||||
self.settings.name = 'Foo Token'
|
self.settings.name = token_name
|
||||||
self.settings.symbol = 'FOO'
|
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 = self.accounts[9]
|
self.settings.sink_address = sink_address
|
||||||
self.sink_address = self.settings.sink_address
|
self.sink_address = self.settings.sink_address
|
||||||
|
|
||||||
o = block_latest()
|
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)
|
o = block_by_number(self.start_block, include_tx=False)
|
||||||
r = self.rpc.do(o)
|
r = rpc.do(o)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.start_time = int(r['timestamp'], 16)
|
self.start_time = int(r['timestamp'], 16)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
self.start_time = int(r['timestamp'])
|
self.start_time = int(r['timestamp'])
|
||||||
|
|
||||||
self.default_supply = 10 ** 12
|
self.default_supply = supply
|
||||||
self.default_supply_cap = int(self.default_supply * 10)
|
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
|
tx_hash = None
|
||||||
o = None
|
o = None
|
||||||
|
logg.debug('mode {} {}'.format(mode, self.settings))
|
||||||
|
self.mode = mode
|
||||||
if mode == 'MultiNocap':
|
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':
|
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':
|
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':
|
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:
|
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)
|
o = receipt(tx_hash)
|
||||||
r = self.rpc.do(o)
|
r = rpc.do(o)
|
||||||
self.assertEqual(r['status'], 1)
|
assert r['status'] == 1
|
||||||
self.start_block = r['block_number']
|
self.start_block = r['block_number']
|
||||||
self.address = r['contract_address']
|
self.address = r['contract_address']
|
||||||
|
|
||||||
o = block_by_number(r['block_number'])
|
o = block_by_number(r['block_number'])
|
||||||
r = self.rpc.do(o)
|
r = rpc.do(o)
|
||||||
self.start_time = r['timestamp']
|
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))
|
logg.debug('contract address {} start block {} start time {}'.format(self.address, self.start_block, self.start_time))
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
chainlib~=0.0.5a1
|
chainlib-eth>=0.0.27,<=0.1.0
|
||||||
eth-erc20~=0.0.10a1
|
eth-erc20~=0.1.11
|
||||||
crypto-dev-signer~=0.4.14b6
|
funga-eth~=0.5.6
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -x
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
export PYTHONPATH=.
|
export PYTHONPATH=.
|
||||||
@@ -16,7 +17,7 @@ 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
|
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py
|
||||||
done
|
done
|
||||||
|
|
||||||
modes=(MultiCap SingleCap)
|
modes=(MultiCap SingleCap)
|
||||||
@@ -31,3 +32,4 @@ done
|
|||||||
#done
|
#done
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
|
set +x
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = erc20-demurrage-token
|
name = erc20-demurrage-token
|
||||||
version = 0.0.2a1
|
version = 0.1.0
|
||||||
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
|
||||||
url = https://gitlab.com/grassrootseconomics/sarafu-token
|
url = https://gitlab.com/ccicnet/erc20-demurrage-token
|
||||||
keywords =
|
keywords =
|
||||||
ethereum
|
ethereum
|
||||||
blockchain
|
blockchain
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from chainlib.eth.tx import receipt
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageDefault
|
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from chainlib.eth.block import (
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageDefault
|
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
@@ -28,179 +28,206 @@ testdir = os.path.dirname(__file__)
|
|||||||
|
|
||||||
class TestBasic(TestDemurrageDefault):
|
class TestBasic(TestDemurrageDefault):
|
||||||
|
|
||||||
# def test_hello(self):
|
def test_hello(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)
|
||||||
# o = c.actual_period(self.address, sender_address=self.accounts[0])
|
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
#
|
|
||||||
# self.backend.time_travel(self.start_time + self.period_seconds + 1)
|
self.backend.time_travel(self.start_time + self.period_seconds + 1)
|
||||||
# o = c.actual_period(self.address, sender_address=self.accounts[0])
|
o = c.actual_period(self.address, sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
#
|
|
||||||
#
|
|
||||||
# def test_balance(self):
|
def test_balance(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)
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
o = receipt(tx_hash)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 1)
|
self.assertEqual(r['status'], 1)
|
||||||
#
|
|
||||||
# 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_of(r)
|
balance = c.parse_balance_of(r)
|
||||||
# self.assertEqual(balance, 1024)
|
self.assertEqual(balance, 1024)
|
||||||
#
|
|
||||||
#
|
|
||||||
# def test_apply_demurrage(self):
|
def test_apply_demurrage_limited(self):
|
||||||
# modifier = (10 ** 38)
|
modifier = (10 ** 28)
|
||||||
#
|
|
||||||
# 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)
|
||||||
#
|
|
||||||
# o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# demurrage_amount = c.parse_demurrage_amount(r)
|
demurrage_amount = c.parse_demurrage_amount(r)
|
||||||
# self.assertEqual(modifier, demurrage_amount)
|
self.assertEqual(modifier, demurrage_amount)
|
||||||
#
|
|
||||||
# o = block_latest()
|
self.backend.time_travel(self.start_time + 120)
|
||||||
# r = self.rpc.do(o)
|
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0], limit=1)
|
||||||
# o = block_by_number(r)
|
r = self.rpc.do(o)
|
||||||
# b = self.rpc.do(o)
|
o = receipt(tx_hash)
|
||||||
# logg.debug('block {} start {}'.format(b['timestamp'], self.start_time))
|
r = self.rpc.do(o)
|
||||||
#
|
self.assertEqual(r['status'], 1)
|
||||||
# self.backend.time_travel(self.start_time + 2)
|
|
||||||
# (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
demurrage_amount = c.parse_demurrage_amount(r)
|
||||||
# r = self.rpc.do(o)
|
modifier_base = 1000000 - self.tax_level
|
||||||
# self.assertEqual(r['status'], 1)
|
modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000)
|
||||||
#
|
self.assertEqual(modifier, demurrage_amount)
|
||||||
# o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
|
||||||
# r = self.rpc.do(o)
|
|
||||||
# demurrage_amount = c.parse_demurrage_amount(r)
|
|
||||||
# self.assertEqual(modifier, demurrage_amount)
|
def test_apply_demurrage(self):
|
||||||
#
|
modifier = (10 ** 28)
|
||||||
# self.backend.time_travel(self.start_time + 61)
|
|
||||||
# (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
# r = self.rpc.do(o)
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
# o = receipt(tx_hash)
|
|
||||||
# r = self.rpc.do(o)
|
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||||
# self.assertEqual(r['status'], 1)
|
r = self.rpc.do(o)
|
||||||
# o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
demurrage_amount = c.parse_demurrage_amount(r)
|
||||||
# r = self.rpc.do(o)
|
self.assertEqual(modifier, demurrage_amount)
|
||||||
# demurrage_amount = c.parse_demurrage_amount(r)
|
|
||||||
# modifier_base = 1000000 - self.tax_level
|
o = block_latest()
|
||||||
# logg.debug('modifier base {}'.format(modifier_base))
|
r = self.rpc.do(o)
|
||||||
# modifier = int(modifier_base * (10 ** 32)) # 38 decimal places minus 6 (1000000)
|
o = block_by_number(r)
|
||||||
# self.assertEqual(modifier, demurrage_amount)
|
b = self.rpc.do(o)
|
||||||
#
|
logg.debug('block {} start {}'.format(b['timestamp'], self.start_time))
|
||||||
# self.backend.time_travel(self.start_time + 601)
|
|
||||||
# (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
self.backend.time_travel(self.start_time + 2)
|
||||||
# r = self.rpc.do(o)
|
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||||
# o = receipt(tx_hash)
|
r = self.rpc.do(o)
|
||||||
# r = self.rpc.do(o)
|
o = receipt(tx_hash)
|
||||||
# self.assertEqual(r['status'], 1)
|
r = self.rpc.do(o)
|
||||||
# o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
self.assertEqual(r['status'], 1)
|
||||||
# r = self.rpc.do(o)
|
|
||||||
# demurrage_amount = c.parse_demurrage_amount(r)
|
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||||
# modifier_base = ((1000000 - self.tax_level) / 1000000) ** 10
|
r = self.rpc.do(o)
|
||||||
# modifier = int(modifier_base * (10 ** 12))
|
demurrage_amount = c.parse_demurrage_amount(r)
|
||||||
#
|
self.assertEqual(modifier, demurrage_amount)
|
||||||
# rounding_tolerance_nano = 4000000 # 0.000004% precision
|
|
||||||
# demurrage_amount_truncate = int(demurrage_amount / (10 ** 26)) # equals 12 decimal places
|
self.backend.time_travel(self.start_time + 61)
|
||||||
# self.assertGreaterEqual(modifier, demurrage_amount_truncate - rounding_tolerance_nano)
|
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||||
# self.assertLessEqual(modifier, demurrage_amount_truncate)
|
r = self.rpc.do(o)
|
||||||
#
|
o = receipt(tx_hash)
|
||||||
#
|
r = self.rpc.do(o)
|
||||||
# def test_mint(self):
|
self.assertEqual(r['status'], 1)
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||||
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
r = self.rpc.do(o)
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
demurrage_amount = c.parse_demurrage_amount(r)
|
||||||
# r = self.rpc.do(o)
|
modifier_base = 1000000 - self.tax_level
|
||||||
# o = receipt(tx_hash)
|
modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000)
|
||||||
# r = self.rpc.do(o)
|
self.assertEqual(modifier, demurrage_amount)
|
||||||
# self.assertEqual(r['status'], 1)
|
|
||||||
#
|
self.backend.time_travel(self.start_time + 601)
|
||||||
# o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# balance = c.parse_balance_of(r)
|
o = receipt(tx_hash)
|
||||||
# self.assertEqual(balance, 1024)
|
r = self.rpc.do(o)
|
||||||
#
|
self.assertEqual(r['status'], 1)
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 976)
|
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
demurrage_amount = c.parse_demurrage_amount(r)
|
||||||
# r = self.rpc.do(o)
|
modifier_base = ((1000000 - self.tax_level) / 1000000) ** 10
|
||||||
# self.assertEqual(r['status'], 1)
|
logg.warning('mod base {}'.format(modifier_base))
|
||||||
#
|
modifier = int(modifier_base * (10 ** 12))
|
||||||
# o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
|
||||||
# r = self.rpc.do(o)
|
rounding_tolerance_nano = 4000000 # 0.000004% precision
|
||||||
# balance = c.parse_balance_of(r)
|
demurrage_amount_truncate = int(demurrage_amount / (10 ** 16)) # equals 38 decimal places - 14 for the modifier magniture - 2 for percent int calc + 6 for token decimals <- TODO verify this calc
|
||||||
# self.assertEqual(balance, 2000)
|
self.assertGreaterEqual(modifier, demurrage_amount_truncate - rounding_tolerance_nano)
|
||||||
#
|
self.assertLessEqual(modifier, demurrage_amount_truncate)
|
||||||
#
|
|
||||||
# self.backend.time_travel(self.start_time + 61)
|
|
||||||
# (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
def test_mint(self):
|
||||||
# r = self.rpc.do(o)
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
# o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
# r = self.rpc.do(o)
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||||
# balance = c.parse_balance_of(r)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(balance, int(2000 * 0.98))
|
o = receipt(tx_hash)
|
||||||
#
|
r = self.rpc.do(o)
|
||||||
#
|
self.assertEqual(r['status'], 1)
|
||||||
# def test_minter_control(self):
|
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||||
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
r = self.rpc.do(o)
|
||||||
#
|
balance = c.parse_balance_of(r)
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
self.assertEqual(balance, 1024)
|
||||||
# self.rpc.do(o)
|
|
||||||
# o = receipt(tx_hash)
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 976)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 0)
|
o = receipt(tx_hash)
|
||||||
#
|
r = self.rpc.do(o)
|
||||||
# (tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[1])
|
self.assertEqual(r['status'], 1)
|
||||||
# self.rpc.do(o)
|
|
||||||
# o = receipt(tx_hash)
|
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 0)
|
balance = c.parse_balance_of(r)
|
||||||
#
|
self.assertEqual(balance, 2000)
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
|
||||||
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
|
||||||
# (tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[1])
|
self.backend.time_travel(self.start_time + 61)
|
||||||
# self.rpc.do(o)
|
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||||
# o = receipt(tx_hash)
|
r = self.rpc.do(o)
|
||||||
# r = self.rpc.do(o)
|
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||||
# self.assertEqual(r['status'], 1)
|
r = self.rpc.do(o)
|
||||||
#
|
balance = c.parse_balance_of(r)
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
self.assertEqual(balance, int(2000 * 0.98))
|
||||||
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
|
||||||
# self.rpc.do(o)
|
def test_minter_control(self):
|
||||||
# o = receipt(tx_hash)
|
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
||||||
# r = self.rpc.do(o)
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
# self.assertEqual(r['status'], 1)
|
|
||||||
#
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
||||||
# (tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[2])
|
self.rpc.do(o)
|
||||||
# self.rpc.do(o)
|
o = receipt(tx_hash)
|
||||||
# o = receipt(tx_hash)
|
r = self.rpc.do(o)
|
||||||
# r = self.rpc.do(o)
|
self.assertEqual(r['status'], 0)
|
||||||
# self.assertEqual(r['status'], 0)
|
|
||||||
#
|
(tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[1])
|
||||||
# (tx_hash, o) = c.remove_minter(self.address, self.accounts[1], self.accounts[1])
|
self.rpc.do(o)
|
||||||
# self.rpc.do(o)
|
o = receipt(tx_hash)
|
||||||
# o = receipt(tx_hash)
|
r = self.rpc.do(o)
|
||||||
# r = self.rpc.do(o)
|
self.assertEqual(r['status'], 0)
|
||||||
# self.assertEqual(r['status'], 1)
|
|
||||||
#
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
# self.rpc.do(o)
|
(tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[1])
|
||||||
# o = receipt(tx_hash)
|
self.rpc.do(o)
|
||||||
# r = self.rpc.do(o)
|
o = receipt(tx_hash)
|
||||||
# self.assertEqual(r['status'], 0)
|
r = self.rpc.do(o)
|
||||||
#
|
self.assertEqual(r['status'], 1)
|
||||||
#
|
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
||||||
|
self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.add_minter(self.address, self.accounts[1], self.accounts[2])
|
||||||
|
self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 0)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.remove_minter(self.address, self.accounts[1], self.accounts[1])
|
||||||
|
self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[1], self.accounts[2], 1024)
|
||||||
|
self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 0)
|
||||||
|
|
||||||
|
|
||||||
def test_base_amount(self):
|
def test_base_amount(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)
|
||||||
@@ -216,78 +243,78 @@ class TestBasic(TestDemurrageDefault):
|
|||||||
amount = c.parse_to_base_amount(r)
|
amount = c.parse_to_base_amount(r)
|
||||||
self.assertEqual(amount, 1020)
|
self.assertEqual(amount, 1020)
|
||||||
|
|
||||||
#
|
|
||||||
# def test_transfer(self):
|
def test_transfer(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)
|
||||||
#
|
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||||
# self.rpc.do(o)
|
self.rpc.do(o)
|
||||||
#
|
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
nonce_oracle = RPCNonceOracle(self.accounts[1], 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)
|
||||||
# (tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[2], 500)
|
(tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[2], 500)
|
||||||
# self.rpc.do(o)
|
self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
o = receipt(tx_hash)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 1)
|
self.assertEqual(r['status'], 1)
|
||||||
#
|
|
||||||
# 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_of(r)
|
balance = c.parse_balance_of(r)
|
||||||
# self.assertEqual(balance, 524)
|
self.assertEqual(balance, 524)
|
||||||
#
|
|
||||||
# o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0])
|
o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# balance = c.parse_balance_of(r)
|
balance = c.parse_balance_of(r)
|
||||||
# self.assertEqual(balance, 500)
|
self.assertEqual(balance, 500)
|
||||||
#
|
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc)
|
nonce_oracle = RPCNonceOracle(self.accounts[2], 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)
|
||||||
# (tx_hash, o) = c.transfer(self.address, self.accounts[2], self.accounts[1], 500)
|
(tx_hash, o) = c.transfer(self.address, self.accounts[2], self.accounts[1], 500)
|
||||||
# self.rpc.do(o)
|
self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
o = receipt(tx_hash)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 1)
|
self.assertEqual(r['status'], 1)
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def test_transfer_from(self):
|
def test_transfer_from(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)
|
||||||
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||||
# self.rpc.do(o)
|
self.rpc.do(o)
|
||||||
#
|
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
|
nonce_oracle = RPCNonceOracle(self.accounts[1], 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)
|
||||||
# (tx_hash, o) = c.approve(self.address, self.accounts[1], self.accounts[2], 500)
|
(tx_hash, o) = c.approve(self.address, self.accounts[1], self.accounts[2], 500)
|
||||||
# self.rpc.do(o)
|
self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
o = receipt(tx_hash)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 1)
|
self.assertEqual(r['status'], 1)
|
||||||
#
|
|
||||||
# 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_of(r)
|
balance = c.parse_balance_of(r)
|
||||||
# self.assertEqual(balance, 1024)
|
self.assertEqual(balance, 1024)
|
||||||
#
|
|
||||||
# nonce_oracle = RPCNonceOracle(self.accounts[2], self.rpc)
|
nonce_oracle = RPCNonceOracle(self.accounts[2], 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)
|
||||||
# (tx_hash, o) = c.transfer_from(self.address, self.accounts[2], self.accounts[1], self.accounts[3], 500)
|
(tx_hash, o) = c.transfer_from(self.address, self.accounts[2], self.accounts[1], self.accounts[3], 500)
|
||||||
# self.rpc.do(o)
|
self.rpc.do(o)
|
||||||
# o = receipt(tx_hash)
|
o = receipt(tx_hash)
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# self.assertEqual(r['status'], 1)
|
self.assertEqual(r['status'], 1)
|
||||||
#
|
|
||||||
# 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_of(r)
|
balance = c.parse_balance_of(r)
|
||||||
# self.assertEqual(balance, 524)
|
self.assertEqual(balance, 524)
|
||||||
#
|
|
||||||
# o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
|
o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
|
||||||
# r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
# balance = c.parse_balance_of(r)
|
balance = c.parse_balance_of(r)
|
||||||
# self.assertEqual(balance, 500)
|
self.assertEqual(balance, 500)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from hexathon import (
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageCap
|
from erc20_demurrage_token.unittest.base import TestDemurrageCap
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
41
python/tests/test_demurrage_ext.py
Normal file
41
python/tests/test_demurrage_ext.py
Normal 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()
|
||||||
@@ -18,7 +18,7 @@ from chainlib.eth.block import (
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageDefault
|
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from chainlib.eth.tx import receipt
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageDefault
|
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from hexathon import (
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageDefault
|
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from hexathon import (
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageUnit
|
from erc20_demurrage_token.unittest.base import TestDemurrageUnit
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import eth_tester
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageDefault
|
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from hexathon import (
|
|||||||
from erc20_demurrage_token import DemurrageToken
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
|
||||||
# test imports
|
# test imports
|
||||||
from tests.base import TestDemurrageSingle
|
from erc20_demurrage_token.unittest.base import TestDemurrageSingle
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ contract DemurrageTokenMultiCap {
|
|||||||
// (this constant x 1000000 is contained within 128 bits)
|
// (this constant x 1000000 is contained within 128 bits)
|
||||||
uint256 constant ppmDivider = 100000000000000000000000000000000;
|
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)
|
// Timestamp of start of periods (time which contract constructor was called)
|
||||||
uint256 public immutable periodStart;
|
uint256 public immutable periodStart;
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ contract DemurrageTokenMultiNocap {
|
|||||||
// (this constant x 1000000 is contained within 128 bits)
|
// (this constant x 1000000 is contained within 128 bits)
|
||||||
uint256 constant ppmDivider = 100000000000000000000000000000000;
|
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)
|
// Timestamp of start of periods (time which contract constructor was called)
|
||||||
uint256 public immutable periodStart;
|
uint256 public immutable periodStart;
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ contract DemurrageTokenSingleCap {
|
|||||||
uint256 constant growthResolutionFactor = 1000000000000;
|
uint256 constant growthResolutionFactor = 1000000000000;
|
||||||
|
|
||||||
// demurrage decimal width; 38 places
|
// 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)
|
// Timestamp of start of periods (time which contract constructor was called)
|
||||||
uint256 public immutable periodStart;
|
uint256 public immutable periodStart;
|
||||||
@@ -311,6 +311,10 @@ contract DemurrageTokenSingleCap {
|
|||||||
|
|
||||||
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
|
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
|
||||||
function applyDemurrage() public returns (bool) {
|
function applyDemurrage() public returns (bool) {
|
||||||
|
return applyDemurrageLimited(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
|
||||||
//uint128 epochPeriodCount;
|
//uint128 epochPeriodCount;
|
||||||
uint256 periodCount;
|
uint256 periodCount;
|
||||||
uint256 lastDemurrageAmount;
|
uint256 lastDemurrageAmount;
|
||||||
@@ -323,6 +327,12 @@ contract DemurrageTokenSingleCap {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lastDemurrageAmount = demurrageAmount;
|
lastDemurrageAmount = demurrageAmount;
|
||||||
|
// safety limit for exponential calculation to ensure that we can always
|
||||||
|
// execute this code no matter how much time passes.
|
||||||
|
if (_rounds > 0 && _rounds < periodCount) {
|
||||||
|
periodCount = _rounds;
|
||||||
|
}
|
||||||
|
|
||||||
demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
|
demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
|
||||||
//demurragePeriod = epochPeriodCount;
|
//demurragePeriod = epochPeriodCount;
|
||||||
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ contract DemurrageTokenSingleCap {
|
|||||||
uint256 constant growthResolutionFactor = 1000000000000;
|
uint256 constant growthResolutionFactor = 1000000000000;
|
||||||
|
|
||||||
// demurrage decimal width; 38 places
|
// 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)
|
// Timestamp of start of periods (time which contract constructor was called)
|
||||||
uint256 public immutable periodStart;
|
uint256 public immutable periodStart;
|
||||||
@@ -278,7 +278,8 @@ 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); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
|
||||||
|
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000)); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
|
||||||
return difference / resolutionFactor;
|
return difference / resolutionFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +308,10 @@ contract DemurrageTokenSingleCap {
|
|||||||
|
|
||||||
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
|
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
|
||||||
function applyDemurrage() public returns (bool) {
|
function applyDemurrage() public returns (bool) {
|
||||||
|
return applyDemurrageLimited(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
|
||||||
//uint128 epochPeriodCount;
|
//uint128 epochPeriodCount;
|
||||||
uint256 periodCount;
|
uint256 periodCount;
|
||||||
uint256 lastDemurrageAmount;
|
uint256 lastDemurrageAmount;
|
||||||
@@ -319,6 +324,13 @@ contract DemurrageTokenSingleCap {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lastDemurrageAmount = demurrageAmount;
|
lastDemurrageAmount = demurrageAmount;
|
||||||
|
|
||||||
|
// safety limit for exponential calculation to ensure that we can always
|
||||||
|
// execute this code no matter how much time passes.
|
||||||
|
if (_rounds > 0 && _rounds < periodCount) {
|
||||||
|
periodCount = _rounds;
|
||||||
|
}
|
||||||
|
|
||||||
demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
|
demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
|
||||||
//demurragePeriod = epochPeriodCount;
|
//demurragePeriod = epochPeriodCount;
|
||||||
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
||||||
|
|||||||
Reference in New Issue
Block a user