WIP rehabilitating test basic

This commit is contained in:
lash 2023-02-09 11:44:20 +00:00
parent ae2c1b4124
commit f785925eb5
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 81 additions and 77 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -24,6 +24,7 @@ from hexathon import (
# local imports # local imports
from erc20_demurrage_token.data import data_dir from erc20_demurrage_token.data import data_dir
from erc20_demurrage_token.fixed import from_fixed
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
@ -100,7 +101,8 @@ class DemurrageToken(ERC20):
@staticmethod @staticmethod
def abi(multi=True, cap=False): 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: if DemurrageToken.__abi.get(name) == None:
f = open(os.path.join(data_dir, name + '.json'), 'r') f = open(os.path.join(data_dir, name + '.json'), 'r')
DemurrageToken.__abi[name] = json.load(f) DemurrageToken.__abi[name] = json.load(f)
@ -110,7 +112,8 @@ class DemurrageToken(ERC20):
@staticmethod @staticmethod
def bytecode(multi=True, cap=False): 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: if DemurrageToken.__bytecode.get(name) == None:
f = open(os.path.join(data_dir, name + '.bin'), 'r') f = open(os.path.join(data_dir, name + '.bin'), 'r')
DemurrageToken.__bytecode[name] = f.read() DemurrageToken.__bytecode[name] = f.read()
@ -561,7 +564,8 @@ class DemurrageToken(ERC20):
@classmethod @classmethod
def parse_demurrage_amount(self, v): 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 @classmethod

View File

@ -1,6 +1,7 @@
# standard imports # standard imports
import logging import logging
import os import os
import math
# external imports # external imports
from chainlib.eth.unittest.ethtester import EthTesterCase from chainlib.eth.unittest.ethtester import EthTesterCase
@ -19,6 +20,10 @@ from erc20_demurrage_token import (
DemurrageTokenSettings, DemurrageTokenSettings,
DemurrageToken, DemurrageToken,
) )
from erc20_demurrage_token.fixed import (
to_fixed,
from_fixed,
)
logg = logging.getLogger() logg = logging.getLogger()
@ -26,8 +31,7 @@ logg = logging.getLogger()
TAX_LEVEL = int(10000 * 2) # 2% TAX_LEVEL = int(10000 * 2) # 2%
# calc "1-(0.98)^(1/518400)" <- 518400 = 30 days of blocks # calc "1-(0.98)^(1/518400)" <- 518400 = 30 days of blocks
# 0.00000003897127107225 # 0.00000003897127107225
#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month PERIOD = 43200
PERIOD = 10
class TestTokenDeploy: class TestTokenDeploy:
@ -41,7 +45,8 @@ class TestTokenDeploy:
self.settings.name = token_name self.settings.name = token_name
self.settings.symbol = token_symbol self.settings.symbol = token_symbol
self.settings.decimals = 6 self.settings.decimals = 6
self.settings.demurrage_level = tax_level ** (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.period_minutes = period
self.settings.sink_address = sink_address self.settings.sink_address = sink_address
self.sink_address = self.settings.sink_address self.sink_address = self.settings.sink_address
@ -59,11 +64,10 @@ class TestTokenDeploy:
self.start_time = int(r['timestamp']) self.start_time = int(r['timestamp'])
self.default_supply = supply self.default_supply = supply
#self.default_supply_cap = int(self.default_supply * 10)
self.default_supply_cap = 0 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 tx_hash = None
o = None o = None
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=0) (tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=0)
@ -100,7 +104,7 @@ class TestDemurrage(EthTesterCase):
def deploy(self, interface): 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_block = self.deployer.start_block
self.start_time = self.deployer.start_time self.start_time = self.deployer.start_time
self.tax_level = self.deployer.tax_level self.tax_level = self.deployer.tax_level
@ -117,6 +121,12 @@ class TestDemurrage(EthTesterCase):
logg.debug('asserted within lower {} <= {} <= {}'.format(lower_target, v, target)) 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): def tearDown(self):
pass pass
@ -130,5 +140,3 @@ class TestDemurrageDefault(TestDemurrage):
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
self.deploy(c) self.deploy(c)
logg.info('deployed with mode {}'.format(self.mode))

View File

@ -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 erc20_demurrage_token.unittest.base import TestDemurrageDefault from erc20_demurrage_token.unittest import TestDemurrageDefault
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger() logg = logging.getLogger()
@ -55,7 +55,8 @@ class TestBasic(TestDemurrageDefault):
def test_apply_demurrage_limited(self): def test_apply_demurrage_limited(self):
modifier = (10 ** 28) #modifier = (10 ** 28)
modifier = 1
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)
@ -65,8 +66,8 @@ class TestBasic(TestDemurrageDefault):
demurrage_amount = c.parse_demurrage_amount(r) demurrage_amount = c.parse_demurrage_amount(r)
self.assertEqual(modifier, demurrage_amount) self.assertEqual(modifier, demurrage_amount)
self.backend.time_travel(self.start_time + 120) self.backend.time_travel(self.start_time + (60 * 43200))
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0], limit=1) (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0], limit=20000)
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)
@ -75,13 +76,12 @@ class TestBasic(TestDemurrageDefault):
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)
modifier_base = 1000000 - self.tax_level self.assert_equal_decimals(0.9906, demurrage_amount, 4)
modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000)
self.assertEqual(modifier, demurrage_amount)
def test_apply_demurrage(self): def test_apply_demurrage(self):
modifier = (10 ** 28) #modifier = (10 ** 28)
modifier = 1
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)
@ -97,7 +97,7 @@ class TestBasic(TestDemurrageDefault):
b = self.rpc.do(o) b = self.rpc.do(o)
logg.debug('block {} start {}'.format(b['timestamp'], self.start_time)) 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]) (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
o = receipt(tx_hash) o = receipt(tx_hash)
@ -107,9 +107,9 @@ class TestBasic(TestDemurrageDefault):
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.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]) (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
o = receipt(tx_hash) o = receipt(tx_hash)
@ -120,28 +120,10 @@ class TestBasic(TestDemurrageDefault):
demurrage_amount = c.parse_demurrage_amount(r) demurrage_amount = c.parse_demurrage_amount(r)
modifier_base = 1000000 - self.tax_level modifier_base = 1000000 - self.tax_level
modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000) modifier = int(modifier_base * (10 ** 22)) # 38 decimal places minus 6 (1000000)
self.assertEqual(modifier, demurrage_amount) self.assert_equal_decimals(0.9604, demurrage_amount, 4)
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)
def test_mint(self): def test_mint_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)
@ -160,16 +142,19 @@ class TestBasic(TestDemurrageDefault):
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, 2000) 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]) (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o) 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]) 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)

View File

@ -90,7 +90,7 @@ contract DemurrageTokenSingleCap {
event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value); event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value);
// New demurrage cache milestone calculated // 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 // When a new period threshold has been crossed
event Period(uint256 _period); event Period(uint256 _period);
@ -214,6 +214,10 @@ contract DemurrageTokenSingleCap {
return true; return true;
} }
function changePeriod() public {
applyDemurrage();
}
// Creates new tokens out of thin air, and allocates them to the given address // Creates new tokens out of thin air, and allocates them to the given address
// Triggers tax // Triggers tax
function mintTo(address _beneficiary, uint256 _amount) external returns (bool) { function mintTo(address _beneficiary, uint256 _amount) external returns (bool) {
@ -221,7 +225,7 @@ contract DemurrageTokenSingleCap {
require(minter[msg.sender], 'ERR_ACCESS'); require(minter[msg.sender], 'ERR_ACCESS');
//changePeriod(); changePeriod();
baseAmount = toBaseAmount(_amount); baseAmount = toBaseAmount(_amount);
supply += _amount; supply += _amount;
increaseBaseBalance(_beneficiary, baseAmount); increaseBaseBalance(_beneficiary, baseAmount);
@ -328,33 +332,38 @@ contract DemurrageTokenSingleCap {
return (block.timestamp - _lastTimestamp) / 60; return (block.timestamp - _lastTimestamp) / 60;
} }
// // 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 (uint256) {
// return applyDemurrageLimited(0); return applyDemurrageLimited(0);
// } }
//
// function applyDemurrageLimited(uint256 _rounds) public returns (bool) { function applyDemurrageLimited(uint256 _rounds) public returns (uint256) {
// uint256 periodCount; int128 v;
// uint256 lastDemurrageAmount; uint256 periodCount;
// int128 periodPoint;
// periodCount = getMinutesDelta(demurrageTimestamp); int128 lastDemurrageAmount;
// if (periodCount == 0) {
// return false; periodCount = getMinutesDelta(demurrageTimestamp);
// } if (periodCount == 0) {
// lastDemurrageAmount = demurrageAmount; return 0;
// }
// // safety limit for exponential calculation to ensure that we can always lastDemurrageAmount = demurrageAmount;
// // execute this code no matter how much time passes.
// if (_rounds > 0 && _rounds < periodCount) { // safety limit for exponential calculation to ensure that we can always
// periodCount = _rounds; // 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); periodPoint = ABDKMath64x64.fromUInt(periodCount);
// emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount); v = ABDKMath64x64.mul(taxLevel, periodPoint);
// return true; 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 // Return timestamp of start of period threshold
function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) { function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) {
@ -436,8 +445,6 @@ contract DemurrageTokenSingleCap {
valuePoint = ABDKMath64x64.fromUInt(_value); valuePoint = ABDKMath64x64.fromUInt(_value);
periodPoint = ABDKMath64x64.fromUInt(_period); 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.mul(taxLevel, periodPoint);
v = ABDKMath64x64.exp(v); v = ABDKMath64x64.exp(v);
v = ABDKMath64x64.mul(valuePoint, v); v = ABDKMath64x64.mul(valuePoint, v);