mirror of
git://holbrook.no/erc20-demurrage-token
synced 2024-11-24 17:06:46 +01:00
WIP rehabilitating test basic
This commit is contained in:
parent
ae2c1b4124
commit
f785925eb5
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -24,6 +24,7 @@ from hexathon import (
|
||||
|
||||
# local imports
|
||||
from erc20_demurrage_token.data import data_dir
|
||||
from erc20_demurrage_token.fixed import from_fixed
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
@ -100,7 +101,8 @@ class DemurrageToken(ERC20):
|
||||
|
||||
@staticmethod
|
||||
def abi(multi=True, cap=False):
|
||||
name = DemurrageToken.__to_contract_name(multi, cap)
|
||||
#name = DemurrageToken.__to_contract_name(multi, cap)
|
||||
name = 'DemurrageTokenSingleNocap'
|
||||
if DemurrageToken.__abi.get(name) == None:
|
||||
f = open(os.path.join(data_dir, name + '.json'), 'r')
|
||||
DemurrageToken.__abi[name] = json.load(f)
|
||||
@ -110,7 +112,8 @@ class DemurrageToken(ERC20):
|
||||
|
||||
@staticmethod
|
||||
def bytecode(multi=True, cap=False):
|
||||
name = DemurrageToken.__to_contract_name(multi, cap)
|
||||
#name = DemurrageToken.__to_contract_name(multi, cap)
|
||||
name = 'DemurrageTokenSingleNocap'
|
||||
if DemurrageToken.__bytecode.get(name) == None:
|
||||
f = open(os.path.join(data_dir, name + '.bin'), 'r')
|
||||
DemurrageToken.__bytecode[name] = f.read()
|
||||
@ -561,7 +564,8 @@ class DemurrageToken(ERC20):
|
||||
|
||||
@classmethod
|
||||
def parse_demurrage_amount(self, v):
|
||||
return abi_decode_single(ABIContractType.UINT256, v)
|
||||
# return abi_decode_single(ABIContractType.UINT256, v)
|
||||
return from_fixed(v)
|
||||
|
||||
|
||||
@classmethod
|
||||
|
@ -1,6 +1,7 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import os
|
||||
import math
|
||||
|
||||
# external imports
|
||||
from chainlib.eth.unittest.ethtester import EthTesterCase
|
||||
@ -19,6 +20,10 @@ from erc20_demurrage_token import (
|
||||
DemurrageTokenSettings,
|
||||
DemurrageToken,
|
||||
)
|
||||
from erc20_demurrage_token.fixed import (
|
||||
to_fixed,
|
||||
from_fixed,
|
||||
)
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
@ -26,8 +31,7 @@ logg = logging.getLogger()
|
||||
TAX_LEVEL = int(10000 * 2) # 2%
|
||||
# calc "1-(0.98)^(1/518400)" <- 518400 = 30 days of blocks
|
||||
# 0.00000003897127107225
|
||||
#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month
|
||||
PERIOD = 10
|
||||
PERIOD = 43200
|
||||
|
||||
|
||||
class TestTokenDeploy:
|
||||
@ -41,7 +45,8 @@ class TestTokenDeploy:
|
||||
self.settings.name = token_name
|
||||
self.settings.symbol = token_symbol
|
||||
self.settings.decimals = 6
|
||||
self.settings.demurrage_level = tax_level ** (1 / period)
|
||||
tax_level_input = to_fixed((1 - (tax_level / 1000000)) ** (1 / period))
|
||||
self.settings.demurrage_level = tax_level_input
|
||||
self.settings.period_minutes = period
|
||||
self.settings.sink_address = sink_address
|
||||
self.sink_address = self.settings.sink_address
|
||||
@ -59,11 +64,10 @@ class TestTokenDeploy:
|
||||
self.start_time = int(r['timestamp'])
|
||||
|
||||
self.default_supply = supply
|
||||
#self.default_supply_cap = int(self.default_supply * 10)
|
||||
self.default_supply_cap = 0
|
||||
|
||||
|
||||
def deploy(self, rpc, deployer_address, interface, mode, supply_cap=0):
|
||||
def deploy(self, rpc, deployer_address, interface, supply_cap=0):
|
||||
tx_hash = None
|
||||
o = None
|
||||
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=0)
|
||||
@ -100,7 +104,7 @@ class TestDemurrage(EthTesterCase):
|
||||
|
||||
|
||||
def deploy(self, interface):
|
||||
self.address = self.deployer.deploy(self.rpc, self.accounts[0], interface, mode, supply_cap=self.default_supply_cap)
|
||||
self.address = self.deployer.deploy(self.rpc, self.accounts[0], interface, 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
|
||||
@ -117,6 +121,12 @@ class TestDemurrage(EthTesterCase):
|
||||
logg.debug('asserted within lower {} <= {} <= {}'.format(lower_target, v, target))
|
||||
|
||||
|
||||
def assert_equal_decimals(self, v, target, precision):
|
||||
target = int(target * (10 ** precision))
|
||||
target = target / (10 ** precision)
|
||||
self.assertEqual(v, target)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@ -130,5 +140,3 @@ class TestDemurrageDefault(TestDemurrage):
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
|
||||
self.deploy(c)
|
||||
|
||||
logg.info('deployed with mode {}'.format(self.mode))
|
||||
|
@ -18,7 +18,7 @@ from chainlib.eth.block import (
|
||||
from erc20_demurrage_token import DemurrageToken
|
||||
|
||||
# test imports
|
||||
from erc20_demurrage_token.unittest.base import TestDemurrageDefault
|
||||
from erc20_demurrage_token.unittest import TestDemurrageDefault
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
@ -55,7 +55,8 @@ class TestBasic(TestDemurrageDefault):
|
||||
|
||||
|
||||
def test_apply_demurrage_limited(self):
|
||||
modifier = (10 ** 28)
|
||||
#modifier = (10 ** 28)
|
||||
modifier = 1
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
@ -65,8 +66,8 @@ class TestBasic(TestDemurrageDefault):
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
|
||||
self.backend.time_travel(self.start_time + 120)
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0], limit=1)
|
||||
self.backend.time_travel(self.start_time + (60 * 43200))
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0], limit=20000)
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
@ -75,13 +76,12 @@ class TestBasic(TestDemurrageDefault):
|
||||
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
modifier_base = 1000000 - self.tax_level
|
||||
modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000)
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
self.assert_equal_decimals(0.9906, demurrage_amount, 4)
|
||||
|
||||
|
||||
def test_apply_demurrage(self):
|
||||
modifier = (10 ** 28)
|
||||
#modifier = (10 ** 28)
|
||||
modifier = 1
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
@ -97,7 +97,7 @@ class TestBasic(TestDemurrageDefault):
|
||||
b = self.rpc.do(o)
|
||||
logg.debug('block {} start {}'.format(b['timestamp'], self.start_time))
|
||||
|
||||
self.backend.time_travel(self.start_time + 2)
|
||||
self.backend.time_travel(self.start_time + (60 * 43200))
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
@ -107,9 +107,9 @@ class TestBasic(TestDemurrageDefault):
|
||||
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)
|
||||
self.assert_equal_decimals(0.98, demurrage_amount, 2)
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
self.backend.time_travel(self.start_time + (60 * 43200 * 2))
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
@ -120,28 +120,10 @@ class TestBasic(TestDemurrageDefault):
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
modifier_base = 1000000 - self.tax_level
|
||||
modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000)
|
||||
self.assertEqual(modifier, demurrage_amount)
|
||||
|
||||
self.backend.time_travel(self.start_time + 601)
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
demurrage_amount = c.parse_demurrage_amount(r)
|
||||
modifier_base = ((1000000 - self.tax_level) / 1000000) ** 10
|
||||
logg.warning('mod base {}'.format(modifier_base))
|
||||
modifier = int(modifier_base * (10 ** 12))
|
||||
|
||||
rounding_tolerance_nano = 4000000 # 0.000004% precision
|
||||
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.assertGreaterEqual(modifier, demurrage_amount_truncate - rounding_tolerance_nano)
|
||||
self.assertLessEqual(modifier, demurrage_amount_truncate)
|
||||
self.assert_equal_decimals(0.9604, demurrage_amount, 4)
|
||||
|
||||
|
||||
def test_mint(self):
|
||||
def test_mint_balance(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], 1024)
|
||||
@ -160,16 +142,19 @@ class TestBasic(TestDemurrageDefault):
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance_of(r)
|
||||
self.assertEqual(balance, 2000)
|
||||
|
||||
|
||||
self.backend.time_travel(self.start_time + 61)
|
||||
self.backend.time_travel(self.start_time + (60 * 43200))
|
||||
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
|
||||
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
balance = c.parse_balance_of(r)
|
||||
|
@ -90,7 +90,7 @@ contract DemurrageTokenSingleCap {
|
||||
event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value);
|
||||
|
||||
// New demurrage cache milestone calculated
|
||||
event Decayed(uint256 indexed _period, uint256 indexed _periodCount, uint256 indexed _oldAmount, uint256 _newAmount);
|
||||
event Decayed(uint256 indexed _period, uint256 indexed _periodCount, int128 indexed _oldAmount, int128 _newAmount);
|
||||
|
||||
// When a new period threshold has been crossed
|
||||
event Period(uint256 _period);
|
||||
@ -214,6 +214,10 @@ contract DemurrageTokenSingleCap {
|
||||
return true;
|
||||
}
|
||||
|
||||
function changePeriod() public {
|
||||
applyDemurrage();
|
||||
}
|
||||
|
||||
// Creates new tokens out of thin air, and allocates them to the given address
|
||||
// Triggers tax
|
||||
function mintTo(address _beneficiary, uint256 _amount) external returns (bool) {
|
||||
@ -221,7 +225,7 @@ contract DemurrageTokenSingleCap {
|
||||
|
||||
require(minter[msg.sender], 'ERR_ACCESS');
|
||||
|
||||
//changePeriod();
|
||||
changePeriod();
|
||||
baseAmount = toBaseAmount(_amount);
|
||||
supply += _amount;
|
||||
increaseBaseBalance(_beneficiary, baseAmount);
|
||||
@ -328,33 +332,38 @@ contract DemurrageTokenSingleCap {
|
||||
return (block.timestamp - _lastTimestamp) / 60;
|
||||
}
|
||||
|
||||
// // Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
|
||||
// function applyDemurrage() public returns (bool) {
|
||||
// return applyDemurrageLimited(0);
|
||||
// }
|
||||
//
|
||||
// function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
|
||||
// uint256 periodCount;
|
||||
// uint256 lastDemurrageAmount;
|
||||
//
|
||||
// periodCount = getMinutesDelta(demurrageTimestamp);
|
||||
// if (periodCount == 0) {
|
||||
// return false;
|
||||
// }
|
||||
// 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));
|
||||
// //demurragePeriod = epochPeriodCount;
|
||||
// demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
||||
// emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
|
||||
// return true;
|
||||
// }
|
||||
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
|
||||
function applyDemurrage() public returns (uint256) {
|
||||
return applyDemurrageLimited(0);
|
||||
}
|
||||
|
||||
function applyDemurrageLimited(uint256 _rounds) public returns (uint256) {
|
||||
int128 v;
|
||||
uint256 periodCount;
|
||||
int128 periodPoint;
|
||||
int128 lastDemurrageAmount;
|
||||
|
||||
periodCount = getMinutesDelta(demurrageTimestamp);
|
||||
if (periodCount == 0) {
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
periodPoint = ABDKMath64x64.fromUInt(periodCount);
|
||||
v = ABDKMath64x64.mul(taxLevel, periodPoint);
|
||||
v = ABDKMath64x64.exp(v);
|
||||
|
||||
demurrageAmount = ABDKMath64x64.mul(demurrageAmount, v);
|
||||
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
||||
emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
|
||||
return periodCount;
|
||||
}
|
||||
|
||||
// Return timestamp of start of period threshold
|
||||
function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) {
|
||||
@ -436,8 +445,6 @@ contract DemurrageTokenSingleCap {
|
||||
valuePoint = ABDKMath64x64.fromUInt(_value);
|
||||
periodPoint = ABDKMath64x64.fromUInt(_period);
|
||||
|
||||
//valuePoint -= ABDKMath64x64.mul(ABDKMath64x64.exp(ABDKMath64x64.mul(taxLevel, periodPoint)), valuePoint);
|
||||
//valuePoint -= ABDKMath64x64.exp(ABDKMath64x64.mul(taxLevel, periodPoint));
|
||||
v = ABDKMath64x64.mul(taxLevel, periodPoint);
|
||||
v = ABDKMath64x64.exp(v);
|
||||
v = ABDKMath64x64.mul(valuePoint, v);
|
||||
|
Loading…
Reference in New Issue
Block a user