Improve redistribution period test

This commit is contained in:
nolash 2021-06-08 11:16:56 +02:00
parent 0dba167af2
commit 12d5711e36
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
8 changed files with 249 additions and 172 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

@ -208,6 +208,28 @@ class DemurrageToken(ERC20):
return o
def to_redistribution(self, contract_address, participants, demurrage_modifier_ppm, value, period, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('toRedistribution')
enc.typ(ABIContractType.UINT256)
enc.typ(ABIContractType.UINT256)
enc.typ(ABIContractType.UINT256)
enc.typ(ABIContractType.UINT256)
enc.uint256(participants)
enc.uint256(demurrage_modifier_ppm)
enc.uint256(value)
enc.uint256(period)
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
return o
def to_redistribution_period(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
o['method'] = 'eth_call'
@ -301,7 +323,7 @@ class DemurrageToken(ERC20):
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx
def actual_period(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('actualPeriod', contract_address, sender_address=sender_address)
@ -374,6 +396,22 @@ class DemurrageToken(ERC20):
return o
def get_distribution_from_redistribution(self, contract_address, redistribution, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('getDistributionFromRedistribution')
enc.typ(ABIContractType.BYTES32)
enc.bytes32(redistribution)
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
o['params'].append('latest')
return o
@classmethod
def parse_actual_period(self, v):
return abi_decode_single(ABIContractType.UINT256, v)

View File

@ -35,9 +35,9 @@ sim.mint(bob, sim.from_units(100))
sim.transfer(alice, carol, sim.from_units(50))
# check that balances have been updated
assert sim.balance(alice) == sim.from_units(50)
assert sim.balance(bob) == sim.from_units(100)
assert sim.balance(carol) == sim.from_units(50)
#assert sim.balance(alice) == sim.from_units(50)
#assert sim.balance(bob) == sim.from_units(100)
#assert sim.balance(carol) == sim.from_units(50)
# advance to next redistribution period
sim.next()

View File

@ -52,69 +52,69 @@ class TestBasic(TestDemurrageDefault):
# r = self.rpc.do(o)
# balance = c.parse_balance_of(r)
# self.assertEqual(balance, 1024)
def test_apply_demurrage(self):
modifier = (10 ** 38)
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
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)
o = block_latest()
r = self.rpc.do(o)
o = block_by_number(r)
b = self.rpc.do(o)
logg.debug('block {} start {}'.format(b['timestamp'], self.start_time))
self.backend.time_travel(self.start_time + 2)
(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)
self.assertEqual(modifier, demurrage_amount)
self.backend.time_travel(self.start_time + 61)
(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
logg.debug('modifier base {}'.format(modifier_base))
modifier = int(modifier_base * (10 ** 32)) # 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
modifier = int(modifier_base * (10 ** 12))
rounding_tolerance_nano = 4000000 # 0.000004% precision
demurrage_amount_truncate = int(demurrage_amount / (10 ** 26)) # equals 12 decimal places
self.assertGreaterEqual(modifier, demurrage_amount_truncate - rounding_tolerance_nano)
self.assertLessEqual(modifier, demurrage_amount_truncate)
#
#
# def test_apply_demurrage(self):
# modifier = (10 ** 38)
#
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
#
# 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)
#
# o = block_latest()
# r = self.rpc.do(o)
# o = block_by_number(r)
# b = self.rpc.do(o)
# logg.debug('block {} start {}'.format(b['timestamp'], self.start_time))
#
# self.backend.time_travel(self.start_time + 2)
# (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)
# self.assertEqual(modifier, demurrage_amount)
#
# self.backend.time_travel(self.start_time + 61)
# (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
# logg.debug('modifier base {}'.format(modifier_base))
# modifier = int(modifier_base * (10 ** 32)) # 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
# modifier = int(modifier_base * (10 ** 12))
#
# rounding_tolerance_nano = 4000000 # 0.000004% precision
# demurrage_amount_truncate = int(demurrage_amount / (10 ** 26)) # equals 12 decimal places
# self.assertGreaterEqual(modifier, demurrage_amount_truncate - rounding_tolerance_nano)
# self.assertLessEqual(modifier, demurrage_amount_truncate)
#
#
# def test_mint(self):
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
@ -201,21 +201,21 @@ class TestBasic(TestDemurrageDefault):
# self.assertEqual(r['status'], 0)
#
#
# def test_base_amount(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)
# self.rpc.do(o)
#
# self.backend.time_travel(self.start_time + 61)
# (tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# o = c.to_base_amount(self.address, 1000, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# amount = c.parse_to_base_amount(r)
# self.assertEqual(amount, 1020)
#
def test_base_amount(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)
self.rpc.do(o)
self.backend.time_travel(self.start_time + 61)
(tx_hash, o) = c.apply_demurrage(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
o = c.to_base_amount(self.address, 1000, sender_address=self.accounts[0])
r = self.rpc.do(o)
amount = c.parse_to_base_amount(r)
self.assertEqual(amount, 1020)
#
# def test_transfer(self):
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)

View File

@ -31,7 +31,7 @@ class TestPeriod(TestDemurrageDefault):
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
self.backend.time_travel(self.start_time + 61)
self.backend.time_travel(self.start_time + self.period_seconds)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.change_period(self.address, self.accounts[0])
@ -63,6 +63,19 @@ class TestPeriod(TestDemurrageDefault):
period = c.parse_actual_period(r)
self.assertEqual(2, period)
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o)
period = c.parse_to_redistribution_item(r)
# allow test code float rounding error to billionth
modifier = (1 - (self.tax_level / 1000000)) ** (self.period_seconds / 60)
modifier *= 10 ** 9
modifier = int(modifier) * (10 ** (38 - 9))
period /= (10 ** (38 - 9))
period = int(period) * (10 ** (38 - 9))
self.assertEqual(modifier, period)
if __name__ == '__main__':
unittest.main()

View File

@ -36,14 +36,32 @@ class TestRedistribution(TestDemurrageUnit):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
demurrage = (self.tax_level / 1000000) * (10^38)
demurrage = (1 - (self.tax_level / 1000000)) * (10**38)
supply = self.default_supply
o = c.get_distribution(self.address, supply, demurrage, sender_address=self.accounts[0])
r = self.rpc.do(o)
distribution = c.parse_get_distribution(r)
expected_distribution = self.default_supply * (self.tax_level / 1000000)
self.assertEqual(distribution, self.default_supply + expected_distribution)
self.assertEqual(distribution, expected_distribution)
def test_distribution_from_redistribution(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
demurrage = (1 - (self.tax_level / 1000000)) * (10**38)
supply = self.default_supply
o = c.to_redistribution(self.address, 0, demurrage, supply, 1, sender_address=self.accounts[0])
redistribution = self.rpc.do(o)
o = c.get_distribution_from_redistribution(self.address, redistribution, self.accounts[0])
r = self.rpc.do(o)
distribution = c.parse_get_distribution(r)
expected_distribution = self.default_supply * (self.tax_level / 1000000)
self.assertEqual(distribution, expected_distribution)
# def test_single_step(self):
@ -93,77 +111,79 @@ class TestRedistribution(TestDemurrageUnit):
# self.assertEqual(balance, expected_balance)
#
#
# def test_single_step_transfer(self):
# nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
#
# mint_amount = 100000000
# half_mint_amount = int(mint_amount / 2)
#
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], mint_amount)
# self.rpc.do(o)
#
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[2], mint_amount)
# self.rpc.do(o)
#
# nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
# c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
# (tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[3], half_mint_amount)
# self.rpc.do(o)
#
# self.backend.time_travel(self.start_time + self.period_seconds)
#
# (tx_hash, o) = c.change_period(self.address, self.accounts[1])
# self.rpc.do(o)
# o = receipt(tx_hash)
# r = self.rpc.do(o)
# self.assertEqual(r['status'], 1)
#
# demurrage_amount = int((self.tax_level / 1000000) * mint_amount)
#
# expected_balance = mint_amount - demurrage_amount
# o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance_of(r)
# self.assertEqual(balance, expected_balance)
#
# half_demurrage_amount = int((self.tax_level / 1000000) * half_mint_amount)
#
# expected_balance = half_mint_amount - half_demurrage_amount
# o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance_of(r)
# self.assertEqual(balance, expected_balance)
#
# o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance_of(r)
# self.assertEqual(balance, expected_balance)
#
# o = c.total_supply(self.address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# supply = c.parse_total_supply(r)
#
#
# o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
# redistribution = self.rpc.do(o)
# o = c.to_redistribution_supply(self.address, redistribution, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# supply = c.parse_to_redistribution_item(r)
def test_single_step_transfer(self):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
mint_amount = 100000000
half_mint_amount = int(mint_amount / 2)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[1], mint_amount)
self.rpc.do(o)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[2], mint_amount)
self.rpc.do(o)
nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc)
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.transfer(self.address, self.accounts[1], self.accounts[3], half_mint_amount)
self.rpc.do(o)
self.backend.time_travel(self.start_time + self.period_seconds)
(tx_hash, o) = c.change_period(self.address, self.accounts[1])
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
demurrage_amount = int((self.tax_level / 1000000) * mint_amount)
expected_balance = mint_amount - demurrage_amount
o = c.balance_of(self.address, self.accounts[2], sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
self.assertEqual(balance, expected_balance)
half_demurrage_amount = int((self.tax_level / 1000000) * half_mint_amount)
expected_balance = half_mint_amount - half_demurrage_amount
o = c.balance_of(self.address, self.accounts[1], sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
self.assertEqual(balance, expected_balance)
o = c.balance_of(self.address, self.accounts[3], sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
self.assertEqual(balance, expected_balance)
o = c.total_supply(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
supply = c.parse_total_supply(r)
o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
redistribution = self.rpc.do(o)
o = c.to_redistribution_supply(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o)
supply = c.parse_to_redistribution_item(r)
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o)
demurrage = c.parse_to_redistribution_item(r)
# o = c.demurrage_amount(self.address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# demurrage = c.parse_demurrage_amount(r)
# logg.debug('\nrediistribution {}\ndemurrage {}\nsupply {}'.format(redistribution, demurrage, supply))
#
# expected_balance = int(supply * (self.tax_level / 1000000))
# expected_balance_tolerance = 1
#
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance_of(r)
# self.assertGreaterEqual(balance, expected_balance - expected_balance_tolerance)
# self.assertLessEqual(balance, expected_balance)
#
logg.debug('\nrediistribution {}\ndemurrage {}\nsupply {}'.format(redistribution, demurrage, supply))
expected_balance = int(supply * (self.tax_level / 1000000))
expected_balance_tolerance = 1
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = c.parse_balance_of(r)
self.assertGreaterEqual(balance, expected_balance - expected_balance_tolerance)
self.assertLessEqual(balance, expected_balance)
if __name__ == '__main__':
unittest.main()

View File

@ -100,7 +100,7 @@ contract DemurrageTokenSingleCap {
// EIP173
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress, uint256 _supplyCap) public {
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint128 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress, uint256 _supplyCap) public {
// ACL setup
owner = msg.sender;
minter[owner] = true;
@ -114,10 +114,11 @@ contract DemurrageTokenSingleCap {
demurrageTimestamp = block.timestamp;
periodStart = demurrageTimestamp;
periodDuration = _periodMinutes * 60;
demurrageAmount = 100000000000000000000000000000000000000; // Represents 38 decimal places, same as resolutionFactor
//demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor
demurrageAmount = 100000000000000000000000000000000000000;
//demurragePeriod = 1;
taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, nanoDivider, 0, 1);
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution);
// Misc settings
@ -215,7 +216,7 @@ contract DemurrageTokenSingleCap {
// Deserializes the redistribution word
// uint95(unused) | uint20(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) private pure returns(bytes32) {
function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) public pure returns(bytes32) {
bytes32 redistribution;
redistribution |= bytes32((_demurrageModifierPpm << shiftRedistributionDemurrage) & maskRedistributionDemurrage);
@ -278,22 +279,27 @@ contract DemurrageTokenSingleCap {
}
function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
return _supply * (nanoDivider - (_demurrageAmount / nanoDivider));
uint256 difference;
difference = _supply * (resolutionFactor - _demurrageAmount); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
return difference / resolutionFactor;
}
function getDistributionFromRedistribution(bytes32 _redistribution) public returns (uint256) {
uint256 redistributionSupply;
uint256 redistributionDemurrage;
redistributionSupply = toRedistributionSupply(_redistribution);
redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
return getDistribution(redistributionSupply, redistributionDemurrage);
}
// Returns the amount sent to the sink address
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
uint256 redistributionSupply;
uint256 redistributionDemurrage;
uint256 unit;
redistributionSupply = toRedistributionSupply(_redistribution);
redistributionDemurrage = resolutionFactor - toRedistributionDemurrageModifier(_redistribution);
if (redistributionDemurrage == 0) {
return 0;
}
unit = getDistribution(redistributionSupply, redistributionDemurrage);
increaseBaseBalance(sinkAddress, toBaseAmount(unit / nanoDivider));
unit = getDistributionFromRedistribution(_redistribution);
increaseBaseBalance(sinkAddress, toBaseAmount(unit));
return unit;
}
@ -401,7 +407,7 @@ contract DemurrageTokenSingleCap {
// Inflates the given amount according to the current demurrage modifier
function toBaseAmount(uint256 _value) public view returns (uint256) {
return (_value * nanoDivider * growthResolutionFactor) / demurrageAmount;
return (_value * resolutionFactor) / demurrageAmount;
}
// Implements ERC20, triggers tax and/or redistribution
@ -451,7 +457,7 @@ contract DemurrageTokenSingleCap {
decreaseBaseBalance(_from, _value);
increaseBaseBalance(_to, _value);
period = actualPeriod();
//period = actualPeriod();
return true;
}