Keep cumulative sink total in state and deduct from upcoming demurrage

This commit is contained in:
lash 2022-05-27 12:51:10 +00:00
parent 18ee9c5f9b
commit 31faa78346
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 99 additions and 76 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

@ -454,16 +454,14 @@ class DemurrageToken(ERC20):
return o return o
def get_distribution_from_redistribution(self, contract_address, redistribution, redistribution_previous, sender_address=ZERO_ADDRESS, id_generator=None): def get_distribution_from_redistribution(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator) j = JSONRPCRequest(id_generator)
o = j.template() o = j.template()
o['method'] = 'eth_call' o['method'] = 'eth_call'
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('getDistributionFromRedistribution') enc.method('getDistributionFromRedistribution')
enc.typ(ABIContractType.BYTES32) enc.typ(ABIContractType.BYTES32)
enc.typ(ABIContractType.BYTES32)
enc.bytes32(redistribution) enc.bytes32(redistribution)
enc.bytes32(redistribution_previous)
data = add_0x(enc.get()) data = add_0x(enc.get())
tx = self.template(sender_address, contract_address) tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data) tx = self.set_code(tx, data)

View File

@ -32,7 +32,7 @@ testdir = os.path.dirname(__file__)
class TestRedistribution(TestDemurrageDefault): class TestRedistribution(TestDemurrageDefault):
def test_redistribution_boundaries(self): def test_redistribution_periods(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)
@ -42,48 +42,93 @@ class TestRedistribution(TestDemurrageDefault):
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[0], supply) (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[0], supply)
self.rpc.do(o) self.rpc.do(o)
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0]) for i in range(1, 10):
r = self.rpc.do(o) logg.debug('execute time travel to period {}'.format(i))
balance = c.parse_balance(r) self.backend.time_travel(self.start_time + (self.period_seconds * i))
logg.debug('balance before {} supply {}'.format(balance, supply)) (tx_hash, o) = c.change_period(self.address, self.accounts[0])
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
self.backend.time_travel(self.start_time + self.period_seconds) o = c.redistributions(self.address, i, sender_address=self.accounts[0])
(tx_hash, o) = c.change_period(self.address, self.accounts[0]) redistribution = self.rpc.do(o)
r = self.rpc.do(o)
o = receipt(tx_hash) o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
self.assertEqual(r['status'], 1) demurrage = c.parse_to_redistribution_item(r)
o = c.redistributions(self.address, 1, sender_address=self.accounts[0]) o = c.redistributions(self.address, i-1, sender_address=self.accounts[0])
r = self.rpc.do(o) redistribution = self.rpc.do(o)
oo = c.to_redistribution_supply(self.address, r, sender_address=self.accounts[0])
rr = self.rpc.do(oo)
oo = c.to_redistribution_demurrage_modifier(self.address, r, sender_address=self.accounts[0])
rr = self.rpc.do(oo)
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0]) o = c.to_redistribution_demurrage_modifier(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
balance = c.parse_balance(r) demurrage_previous = c.parse_to_redistribution_item(r)
self.backend.time_travel(self.start_time + self.period_seconds * 2 + 1) o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
(tx_hash, o) = c.change_period(self.address, self.accounts[0]) r = self.rpc.do(o)
r = self.rpc.do(o) balance_sink = c.parse_balance(r)
o = receipt(tx_hash) o = c.balance_of(self.address, self.accounts[0], sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
self.assertEqual(r['status'], 1) balance_minter = c.parse_balance(r)
o = c.redistributions(self.address, 2, sender_address=self.accounts[0]) logg.debug('testing sink {} mint {} adds up to supply {} with demurrage between {} and {}'.format(balance_sink, balance_minter, supply, demurrage_previous, demurrage))
r = self.rpc.do(o)
oo = c.to_redistribution_supply(self.address, r, sender_address=self.accounts[0])
rr = self.rpc.do(oo)
oo = c.to_redistribution_demurrage_modifier(self.address, r, sender_address=self.accounts[0])
rr = self.rpc.do(oo)
o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0]) self.assert_within_lower(balance_minter + balance_sink, supply, 0.001)
r = self.rpc.do(o)
balance = c.parse_balance(r) # def test_redistribution_boundaries(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**28)
# supply = self.default_supply
#
# (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[0], supply)
# self.rpc.do(o)
#
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance(r)
# logg.debug('balance before {} supply {}'.format(balance, supply))
#
# self.backend.time_travel(self.start_time + self.period_seconds)
# (tx_hash, o) = c.change_period(self.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.redistributions(self.address, 1, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# oo = c.to_redistribution_supply(self.address, r, sender_address=self.accounts[0])
# rr = self.rpc.do(oo)
# oo = c.to_redistribution_demurrage_modifier(self.address, r, sender_address=self.accounts[0])
# rr = self.rpc.do(oo)
#
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance(r)
#
# self.backend.time_travel(self.start_time + self.period_seconds * 2 + 1)
# (tx_hash, o) = c.change_period(self.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.redistributions(self.address, 2, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# oo = c.to_redistribution_supply(self.address, r, sender_address=self.accounts[0])
# rr = self.rpc.do(oo)
# oo = c.to_redistribution_demurrage_modifier(self.address, r, sender_address=self.accounts[0])
# rr = self.rpc.do(oo)
#
# o = c.balance_of(self.address, self.sink_address, sender_address=self.accounts[0])
# r = self.rpc.do(o)
# balance = c.parse_balance(r)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -51,22 +51,19 @@ class TestRedistribution(TestDemurrageUnit):
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)
demurrage_previous = (1 - (self.tax_level / 100000)) * (10**28) demurrage = (1 - (self.tax_level / 100000)) * (10**28)
demurrage = (1 - ((self.tax_level * 1.33) / 100000)) * (10**28)
logg.debug('demurrage then {} now {}'.format(demurrage_previous, demurrage)) logg.debug('demurrage {}'.format(demurrage))
supply = self.default_supply supply = self.default_supply
o = c.to_redistribution(self.address, 0, demurrage_previous, supply, 1, sender_address=self.accounts[0])
redistribution_previous = self.rpc.do(o)
o = c.to_redistribution(self.address, 0, demurrage, supply, 2, sender_address=self.accounts[0]) o = c.to_redistribution(self.address, 0, demurrage, supply, 2, sender_address=self.accounts[0])
redistribution = self.rpc.do(o) redistribution = self.rpc.do(o)
o = c.get_distribution_from_redistribution(self.address, redistribution, redistribution_previous, self.accounts[0]) o = c.get_distribution_from_redistribution(self.address, redistribution, self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
distribution = c.parse_get_distribution(r) distribution = c.parse_get_distribution(r)
expected_distribution = self.default_supply * (((self.tax_level * 1.33) - self.tax_level) / 100000) #expected_distribution = self.default_supply * (((self.tax_level * 1.33) - self.tax_level) / 100000)
expected_distribution = (self.default_supply * self.tax_level) / 100000
logg.debug('distribution {} supply {}'.format(distribution, self.default_supply)) logg.debug('distribution {} supply {}'.format(distribution, self.default_supply))
self.assert_within_lower(distribution, expected_distribution, 1000) self.assert_within_lower(distribution, expected_distribution, 1000)

View File

@ -22,8 +22,6 @@ contract DemurrageTokenSingleCap {
uint256 public demurrageStart; uint256 public demurrageStart;
// Cached demurrage period; the period for which demurrageAmount was calculated
//uint128 public demurragePeriod;
// Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated // Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
uint256 public demurrageTimestamp; uint256 public demurrageTimestamp;
@ -47,8 +45,8 @@ contract DemurrageTokenSingleCap {
// Last executed period // Last executed period
uint256 public lastPeriod; uint256 public lastPeriod;
// Minimum amount of (demurraged) tokens an account must spend to participate in redistribution for a particular period // Last sink redistribution amount
//uint256 public minimumParticipantSpend; uint256 public totalSink;
// 128 bit resolution of the demurrage divisor // 128 bit resolution of the demurrage divisor
// (this constant x 1000000 is contained within 128 bits) // (this constant x 1000000 is contained within 128 bits)
@ -116,19 +114,14 @@ contract DemurrageTokenSingleCap {
demurrageTimestamp = block.timestamp; demurrageTimestamp = block.timestamp;
periodStart = demurrageTimestamp; periodStart = demurrageTimestamp;
periodDuration = _periodMinutes * 60; periodDuration = _periodMinutes * 60;
//demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor
//demurrageAmount = 100000000000000000000000000000000000000;
//demurrageAmount = 10000000000000000000000000000;
demurrageAmount = uint128(nanoDivider) * 100; demurrageAmount = uint128(nanoDivider) * 100;
demurrageStart = demurrageAmount; demurrageStart = demurrageAmount;
//demurragePeriod = 1;
taxLevel = _taxLevelMinute; // Represents 38 decimal places taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1); bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution); redistributions.push(initialRedistribution);
// Misc settings // Misc settings
sinkAddress = _defaultSinkAddress; sinkAddress = _defaultSinkAddress;
//minimumParticipantSpend = 10 ** uint256(_decimals);
} }
@ -160,10 +153,8 @@ contract DemurrageTokenSingleCap {
baseBalance = baseBalanceOf(_account); baseBalance = baseBalanceOf(_account);
//periodCount = actualPeriod() - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp); periodCount = getMinutesDelta(demurrageTimestamp);
//currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount)); currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount));
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000); return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
@ -281,7 +272,6 @@ contract DemurrageTokenSingleCap {
bytes32 lastRedistribution; bytes32 lastRedistribution;
uint256 currentPeriod; uint256 currentPeriod;
//lastRedistribution = redistributions[redistributions.length-1];
lastRedistribution = redistributions[lastPeriod]; lastRedistribution = redistributions[lastPeriod];
currentPeriod = this.actualPeriod(); currentPeriod = this.actualPeriod();
if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) { if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
@ -293,30 +283,29 @@ 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 * 10000000000));
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000)); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
return difference / resolutionFactor; return difference / resolutionFactor;
} }
function getDistributionFromRedistribution(bytes32 _redistribution, bytes32 _redistributionPrevious) public returns (uint256) { function getDistributionFromRedistribution(bytes32 _redistribution) public returns (uint256) {
uint256 redistributionSupply; uint256 redistributionSupply;
uint256 redistributionDemurrage; uint256 redistributionDemurrage;
uint256 redistributionDemurragePrevious;
redistributionSupply = toRedistributionSupply(_redistribution); redistributionSupply = toRedistributionSupply(_redistribution);
redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution); redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
redistributionDemurragePrevious = toRedistributionDemurrageModifier(_redistributionPrevious);
redistributionDemurrage = demurrageStart - (redistributionDemurragePrevious - redistributionDemurrage);
return getDistribution(redistributionSupply, redistributionDemurrage); return getDistribution(redistributionSupply, redistributionDemurrage);
} }
// Returns the amount sent to the sink address // Returns the amount sent to the sink address
function applyDefaultRedistribution(bytes32 _redistribution, bytes32 _redistributionPrevious) private returns (uint256) { function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
uint256 unit; uint256 unit;
uint256 baseUnit;
unit = getDistributionFromRedistribution(_redistribution, _redistributionPrevious); unit = getDistributionFromRedistribution(_redistribution);
increaseBaseBalance(sinkAddress, toBaseAmount(unit)); baseUnit = toBaseAmount(unit) - totalSink;
increaseBaseBalance(sinkAddress, baseUnit);
lastPeriod += 1; lastPeriod += 1;
totalSink += baseUnit;
return unit; return unit;
} }
@ -331,13 +320,9 @@ contract DemurrageTokenSingleCap {
} }
function applyDemurrageLimited(uint256 _rounds) public returns (bool) { function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
//uint128 epochPeriodCount;
uint256 periodCount; uint256 periodCount;
uint256 lastDemurrageAmount; uint256 lastDemurrageAmount;
//epochPeriodCount = actualPeriod();
//periodCount = epochPeriodCount - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp); periodCount = getMinutesDelta(demurrageTimestamp);
if (periodCount == 0) { if (periodCount == 0) {
return false; return false;
@ -400,7 +385,7 @@ contract DemurrageTokenSingleCap {
nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod); nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod);
redistributions.push(nextRedistribution); redistributions.push(nextRedistribution);
applyDefaultRedistribution(nextRedistribution, currentRedistribution); applyDefaultRedistribution(nextRedistribution);
emit Period(nextPeriod); emit Period(nextPeriod);
return true; return true;
} }
@ -435,7 +420,6 @@ contract DemurrageTokenSingleCap {
// Inflates the given amount according to the current demurrage modifier // Inflates the given amount according to the current demurrage modifier
function toBaseAmount(uint256 _value) public view returns (uint256) { function toBaseAmount(uint256 _value) public view returns (uint256) {
//return (_value * resolutionFactor) / demurrageAmount;
return (_value * resolutionFactor) / (demurrageAmount * 10000000000); return (_value * resolutionFactor) / (demurrageAmount * 10000000000);
} }
@ -486,7 +470,6 @@ contract DemurrageTokenSingleCap {
decreaseBaseBalance(_from, _value); decreaseBaseBalance(_from, _value);
increaseBaseBalance(_to, _value); increaseBaseBalance(_to, _value);
//period = actualPeriod();
return true; return true;
} }