Rehabilitate change period

This commit is contained in:
lash 2023-02-10 05:02:24 +00:00
parent 3333d50f98
commit 555b0b1724
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 138 additions and 129 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

@ -29,6 +29,28 @@ from erc20_demurrage_token.fixed import from_fixed
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
class DemurrageRedistribution:
def __init__(self, v):
d = ABIContractDecoder()
v = strip_0x(v)
d.typ(ABIContractType.UINT256)
d.typ(ABIContractType.UINT256)
d.typ(ABIContractType.BYTES32)
d.val(v[:64])
d.val(v[64:128])
d.val(v[128:192])
r = d.decode()
self.period = r[0]
self.value = r[1]
self.demurrage = from_fixed(r[2])
def __str__(self):
return 'period {} value {} demurrage {}'.format(self.period, self.value, self.demurrage)
class DemurrageTokenSettings: class DemurrageTokenSettings:
def __init__(self): def __init__(self):
@ -315,7 +337,7 @@ class DemurrageToken(ERC20):
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('toRedistributionPeriod') enc.method('toRedistributionPeriod')
v = strip_0x(redistribution) v = strip_0x(redistribution)
enc.typ_literal('(uint32,uint72,uint104)') enc.typ_literal('(uint32,uint72,uint64)')
enc.bytes32(v[:64]) enc.bytes32(v[:64])
enc.bytes32(v[64:128]) enc.bytes32(v[64:128])
enc.bytes32(v[128:192]) enc.bytes32(v[128:192])
@ -356,7 +378,7 @@ class DemurrageToken(ERC20):
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('toRedistributionSupply') enc.method('toRedistributionSupply')
v = strip_0x(redistribution) v = strip_0x(redistribution)
enc.typ_literal('(uint32,uint72,uint104)') enc.typ_literal('(uint32,uint72,uint64)')
enc.bytes32(v[:64]) enc.bytes32(v[:64])
enc.bytes32(v[64:128]) enc.bytes32(v[64:128])
enc.bytes32(v[128:192]) enc.bytes32(v[128:192])
@ -376,7 +398,7 @@ class DemurrageToken(ERC20):
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('toRedistributionDemurrageModifier') enc.method('toRedistributionDemurrageModifier')
v = strip_0x(redistribution) v = strip_0x(redistribution)
enc.typ_literal('(uint32,uint72,uint104)') enc.typ_literal('(uint32,uint72,uint64)')
enc.bytes32(v[:64]) enc.bytes32(v[:64])
enc.bytes32(v[64:128]) enc.bytes32(v[64:128])
enc.bytes32(v[128:192]) enc.bytes32(v[128:192])
@ -580,16 +602,18 @@ class DemurrageToken(ERC20):
@classmethod @classmethod
def parse_redistributions(self, v): def parse_redistributions(self, v):
d = ABIContractDecoder() return strip_0x(v)
v = strip_0x(v) #return DemurrageRedistribution(v)
d.typ(ABIContractType.BYTES32) # d = ABIContractDecoder()
d.typ(ABIContractType.BYTES32) # v = strip_0x(v)
d.typ(ABIContractType.BYTES32) # d.typ(ABIContractType.BYTES32)
d.val(v[:64]) # d.typ(ABIContractType.BYTES32)
d.val(v[64:128]) # d.typ(ABIContractType.BYTES32)
d.val(v[128:192]) # d.val(v[:64])
r = d.decode() # d.val(v[64:128])
return ''.join(r) # d.val(v[128:192])
# r = d.decode()
# return ''.join(r)
@classmethod @classmethod
@ -640,3 +664,4 @@ class DemurrageToken(ERC20):
@classmethod @classmethod
def parse_total_burned(self, v): def parse_total_burned(self, v):
return abi_decode_single(ABIContractType.UINT256, v) return abi_decode_single(ABIContractType.UINT256, v)

View File

@ -19,9 +19,10 @@ from chainlib.eth.contract import (
# local imports # local imports
from erc20_demurrage_token import DemurrageToken from erc20_demurrage_token import DemurrageToken
from erc20_demurrage_token.token import DemurrageRedistribution
# 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()
@ -57,15 +58,6 @@ class TestPeriod(TestDemurrageDefault):
period = c.parse_to_redistribution_period(r) period = c.parse_to_redistribution_period(r)
self.assertEqual(2, period) self.assertEqual(2, period)
o = c.redistributions(self.address, 1, sender_address=self.accounts[0])
r = self.rpc.do(o)
redistribution = c.parse_redistributions(r)
o = c.to_redistribution_period(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o)
period = c.parse_to_redistribution_period(r)
self.assertEqual(2, period)
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)
period = c.parse_actual_period(r) period = c.parse_actual_period(r)
@ -74,6 +66,7 @@ class TestPeriod(TestDemurrageDefault):
o = c.to_redistribution_demurrage_modifier(self.address, redistribution, 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)
period = c.parse_to_redistribution_item(r) period = c.parse_to_redistribution_item(r)
redistro = DemurrageRedistribution(redistribution)
# allow test code float rounding error to billionth # allow test code float rounding error to billionth
modifier = (1 - (self.tax_level / 1000000)) ** (self.period_seconds / 60) modifier = (1 - (self.tax_level / 1000000)) ** (self.period_seconds / 60)

View File

@ -18,7 +18,8 @@ from hexathon import (
from erc20_demurrage_token import DemurrageToken from erc20_demurrage_token import DemurrageToken
# test imports # test imports
from erc20_demurrage_token.unittest.base import TestDemurrageSingle from erc20_demurrage_token.unittest import TestDemurrageDefault
from erc20_demurrage_token.fixed import to_fixed
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger() logg = logging.getLogger()
@ -26,11 +27,9 @@ logg = logging.getLogger()
testdir = os.path.dirname(__file__) testdir = os.path.dirname(__file__)
class TestRedistributionSingle(TestDemurrageSingle): class TestRedistributionSingle(TestDemurrageDefault):
def test_single_even_if_multiple(self): def test_single_even_if_multiple(self):
mint_amount = 100000000 mint_amount = 100000000
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
@ -64,7 +63,7 @@ class TestRedistributionSingle(TestDemurrageSingle):
r = self.rpc.do(o) r = self.rpc.do(o)
self.assertEqual(r['status'], 1) self.assertEqual(r['status'], 1)
tax_modifier = (1 - (self.tax_level / 1000000)) ** 10 tax_modifier = 0.98
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(r) balance = c.parse_balance(r)

View File

@ -9,7 +9,7 @@ contract DemurrageTokenSingleCap {
struct redistributionItem { struct redistributionItem {
uint32 period; uint32 period;
uint72 value; uint72 value;
uint40 demurrage; uint64 demurrage;
} }
redistributionItem[] public redistributions; // uint51(unused) | uint64(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period) redistributionItem[] public redistributions; // uint51(unused) | uint64(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
@ -99,7 +99,8 @@ contract DemurrageTokenSingleCap {
event Redistribution(address indexed _account, uint256 indexed _period, uint256 _value); event Redistribution(address indexed _account, uint256 indexed _period, uint256 _value);
// Temporary event used in development, will be removed on prod // Temporary event used in development, will be removed on prod
event Debug(bytes32 _foo); //event Debug(bytes32 _foo);
event Debug(int128 indexed _foo, uint256 indexed _bar);
// Emitted when tokens are burned // Emitted when tokens are burned
event Burn(address indexed _burner, uint256 _value); event Burn(address indexed _burner, uint256 _value);
@ -128,9 +129,8 @@ contract DemurrageTokenSingleCap {
periodDuration = _periodMinutes * 60; periodDuration = _periodMinutes * 60;
demurrageAmount = ABDKMath64x64.fromUInt(1); demurrageAmount = ABDKMath64x64.fromUInt(1);
//taxLevel = ABDKMath64x64.mul(ABDKMath64x64.ln(ABDKMath64x64.sub(demurrageAmount, , ABDKMath64x64.fromUInt(_periodMinutes));
taxLevel = ABDKMath64x64.ln(_taxLevel); taxLevel = ABDKMath64x64.ln(_taxLevel);
initialRedistribution = toRedistribution(0, uint40(uint128(demurrageAmount)), 0, 1); initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution); redistributions.push(initialRedistribution);
// Misc settings // Misc settings
@ -170,8 +170,6 @@ contract DemurrageTokenSingleCap {
currentDemurragedAmount = ABDKMath64x64.mul(baseBalance, demurrageAmount); currentDemurragedAmount = ABDKMath64x64.mul(baseBalance, demurrageAmount);
return decayBy(ABDKMath64x64.toUInt(currentDemurragedAmount), periodCount); return decayBy(ABDKMath64x64.toUInt(currentDemurragedAmount), periodCount);
//return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
} }
// Balance unmodified by demurrage // Balance unmodified by demurrage
@ -214,10 +212,6 @@ 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) {
@ -235,12 +229,12 @@ contract DemurrageTokenSingleCap {
} }
// Deserializes the redistribution word // Deserializes the redistribution word
function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) public pure returns(redistributionItem memory) { function toRedistribution(uint256 _participants, int128 _demurrageModifier, uint256 _value, uint256 _period) public pure returns(redistributionItem memory) {
redistributionItem memory redistribution; redistributionItem memory redistribution;
redistribution.period = uint32(_period); redistribution.period = uint32(_period);
redistribution.value = uint72(_value); redistribution.value = uint72(_value);
redistribution.demurrage = uint40(_demurrageModifierPpm); redistribution.demurrage = uint64(uint128(_demurrageModifier) & 0xffffffffffffffff);
return redistribution; return redistribution;
} }
@ -256,8 +250,14 @@ contract DemurrageTokenSingleCap {
} }
// Serializes the number of participants part of the redistribution word // Serializes the number of participants part of the redistribution word
function toRedistributionDemurrageModifier(redistributionItem memory _redistribution) public pure returns (uint256) { function toRedistributionDemurrageModifier(redistributionItem memory _redistribution) public pure returns (int128) {
return uint256(_redistribution.demurrage); int128 r;
r = int128(int64(_redistribution.demurrage) & int128(0x0000000000000000ffffffffffffffff));
if (r == 0) {
r = ABDKMath64x64.fromUInt(1);
}
return r;
} }
@ -284,48 +284,87 @@ contract DemurrageTokenSingleCap {
return uint128((block.timestamp - periodStart) / periodDuration + 1); return uint128((block.timestamp - periodStart) / periodDuration + 1);
} }
// // Retrieve next redistribution if the period threshold has been crossed // Retrieve next redistribution if the period threshold has been crossed
// function checkPeriod() private view returns (redistributionItem memory) { function checkPeriod() private view returns (redistributionItem memory) {
// redistributionItem memory lastRedistribution; redistributionItem memory lastRedistribution;
// redistributionItem memory emptyRedistribution; redistributionItem memory emptyRedistribution;
// uint256 currentPeriod; uint256 currentPeriod;
//
// lastRedistribution = redistributions[lastPeriod]; lastRedistribution = redistributions[lastPeriod];
// currentPeriod = this.actualPeriod(); currentPeriod = this.actualPeriod();
// if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) { if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
// return emptyRedistribution; return emptyRedistribution;
// } }
// return lastRedistribution; return lastRedistribution;
// } }
function getDistribution(uint256 _supply, int128 _demurrageAmount) public pure returns (uint256) {
int128 difference;
// function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
// uint256 difference;
//
// difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000)); // difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000));
// return difference / resolutionFactor; // return difference / resolutionFactor;
// } difference = ABDKMath64x64.mul(ABDKMath64x64.fromUInt(_supply), _demurrageAmount);
return ABDKMath64x64.toUInt(difference);
//return _supply;
}
// function getDistributionFromRedistribution(redistributionItem memory _redistribution) public returns (uint256) { function getDistributionFromRedistribution(redistributionItem memory _redistribution) public returns (uint256) {
// uint256 redistributionSupply; uint256 redistributionSupply;
// uint256 redistributionDemurrage; int128 redistributionDemurrage;
//
// redistributionSupply = toRedistributionSupply(_redistribution); redistributionSupply = toRedistributionSupply(_redistribution);
// redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution); redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
// 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(redistributionItem memory _redistribution) private returns (uint256) { function applyDefaultRedistribution(redistributionItem memory _redistribution) private returns (uint256) {
// uint256 unit; uint256 unit;
// uint256 baseUnit; uint256 baseUnit;
//
// unit = getDistributionFromRedistribution(_redistribution); unit = getDistributionFromRedistribution(_redistribution);
// baseUnit = toBaseAmount(unit) - totalSink; baseUnit = toBaseAmount(unit) - totalSink;
// increaseBaseBalance(sinkAddress, baseUnit); increaseBaseBalance(sinkAddress, baseUnit);
// lastPeriod += 1; emit Redistribution(sinkAddress, _redistribution.period, unit);
// totalSink += baseUnit; lastPeriod += 1;
// return unit; totalSink += baseUnit;
// } return unit;
}
// Recalculate the demurrage modifier for the new period
// Note that the supply for the consecutive period will be taken at the time of code execution, and thus not necessarily at the time when the redistribution period threshold was crossed.
function changePeriod() public returns (bool) {
redistributionItem memory currentRedistribution;
redistributionItem memory nextRedistribution;
redistributionItem memory lastRedistribution;
uint256 currentPeriod;
int128 lastDemurrageAmount;
int128 nextRedistributionDemurrage;
uint256 demurrageCounts;
uint256 nextPeriod;
applyDemurrage();
currentRedistribution = checkPeriod();
if (isEmptyRedistribution(currentRedistribution)) {
return false;
}
// calculate the decay from previous redistributino
lastRedistribution = redistributions[lastPeriod];
currentPeriod = toRedistributionPeriod(currentRedistribution);
nextPeriod = currentPeriod + 1;
lastDemurrageAmount = toRedistributionDemurrageModifier(lastRedistribution);
demurrageCounts = periodDuration / 60;
nextRedistributionDemurrage = ABDKMath64x64.mul(taxLevel, ABDKMath64x64.fromUInt(demurrageCounts));
nextRedistributionDemurrage = lastDemurrageAmount - ABDKMath64x64.exp(nextRedistributionDemurrage);
nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply(), nextPeriod);
redistributions.push(nextRedistribution);
applyDefaultRedistribution(nextRedistribution);
emit Period(nextPeriod);
return true;
}
// Calculate the time delta in whole minutes passed between given timestamp and current timestamp // Calculate the time delta in whole minutes passed between given timestamp and current timestamp
function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) { function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) {
@ -388,53 +427,6 @@ contract DemurrageTokenSingleCap {
return true; return true;
} }
// // Recalculate the demurrage modifier for the new period
// // Note that the supply for the consecutive period will be taken at the time of code execution, and thus not necessarily at the time when the redistribution period threshold was crossed.
// function changePeriod() public returns (bool) {
// redistributionItem memory currentRedistribution;
// redistributionItem memory nextRedistribution;
// redistributionItem memory lastRedistribution;
// uint256 currentPeriod;
// uint256 lastDemurrageAmount;
// uint256 nextRedistributionDemurrage;
// uint256 demurrageCounts;
// uint256 nextPeriod;
//
// applyDemurrage();
// currentRedistribution = checkPeriod();
// if (isEmptyRedistribution(currentRedistribution)) {
// return false;
// }
//
// // calculate the decay from previous redistributino
// lastRedistribution = redistributions[lastPeriod];
// currentPeriod = toRedistributionPeriod(currentRedistribution);
// nextPeriod = currentPeriod + 1;
// lastDemurrageAmount = toRedistributionDemurrageModifier(lastRedistribution);
// demurrageCounts = periodDuration / 60;
// nextRedistributionDemurrage = decayBy(lastDemurrageAmount, demurrageCounts);
//
// nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply(), nextPeriod);
// redistributions.push(nextRedistribution);
//
// applyDefaultRedistribution(nextRedistribution);
// emit Period(nextPeriod);
// return true;
// }
//
// // Reverse a value reduced by demurrage by the given period to its original value
//// function growBy(uint256 _value, uint256 _period) public view returns (uint256) {
//// uint256 valueFactor;
//// uint256 truncatedTaxLevel;
////
//// valueFactor = growthResolutionFactor;
//// truncatedTaxLevel = taxLevel / nanoDivider;
////
//// for (uint256 i = 0; i < _period; i++) {
//// valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
//// }
//// return (valueFactor * _value) / growthResolutionFactor;
//// }
// Calculate a value reduced by demurrage by the given period // Calculate a value reduced by demurrage by the given period
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) { function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {