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__)
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:
def __init__(self):
@ -315,7 +337,7 @@ class DemurrageToken(ERC20):
enc = ABIContractEncoder()
enc.method('toRedistributionPeriod')
v = strip_0x(redistribution)
enc.typ_literal('(uint32,uint72,uint104)')
enc.typ_literal('(uint32,uint72,uint64)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
@ -356,7 +378,7 @@ class DemurrageToken(ERC20):
enc = ABIContractEncoder()
enc.method('toRedistributionSupply')
v = strip_0x(redistribution)
enc.typ_literal('(uint32,uint72,uint104)')
enc.typ_literal('(uint32,uint72,uint64)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
@ -376,7 +398,7 @@ class DemurrageToken(ERC20):
enc = ABIContractEncoder()
enc.method('toRedistributionDemurrageModifier')
v = strip_0x(redistribution)
enc.typ_literal('(uint32,uint72,uint104)')
enc.typ_literal('(uint32,uint72,uint64)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
@ -580,16 +602,18 @@ class DemurrageToken(ERC20):
@classmethod
def parse_redistributions(self, v):
d = ABIContractDecoder()
v = strip_0x(v)
d.typ(ABIContractType.BYTES32)
d.typ(ABIContractType.BYTES32)
d.typ(ABIContractType.BYTES32)
d.val(v[:64])
d.val(v[64:128])
d.val(v[128:192])
r = d.decode()
return ''.join(r)
return strip_0x(v)
#return DemurrageRedistribution(v)
# d = ABIContractDecoder()
# v = strip_0x(v)
# d.typ(ABIContractType.BYTES32)
# d.typ(ABIContractType.BYTES32)
# d.typ(ABIContractType.BYTES32)
# d.val(v[:64])
# d.val(v[64:128])
# d.val(v[128:192])
# r = d.decode()
# return ''.join(r)
@classmethod
@ -640,3 +664,4 @@ class DemurrageToken(ERC20):
@classmethod
def parse_total_burned(self, v):
return abi_decode_single(ABIContractType.UINT256, v)

View File

@ -19,9 +19,10 @@ from chainlib.eth.contract import (
# local imports
from erc20_demurrage_token import DemurrageToken
from erc20_demurrage_token.token import DemurrageRedistribution
# 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()
@ -57,15 +58,6 @@ class TestPeriod(TestDemurrageDefault):
period = c.parse_to_redistribution_period(r)
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])
r = self.rpc.do(o)
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])
r = self.rpc.do(o)
period = c.parse_to_redistribution_item(r)
redistro = DemurrageRedistribution(redistribution)
# allow test code float rounding error to billionth
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
# 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)
logg = logging.getLogger()
@ -26,11 +27,9 @@ logg = logging.getLogger()
testdir = os.path.dirname(__file__)
class TestRedistributionSingle(TestDemurrageSingle):
class TestRedistributionSingle(TestDemurrageDefault):
def test_single_even_if_multiple(self):
mint_amount = 100000000
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
@ -64,7 +63,7 @@ class TestRedistributionSingle(TestDemurrageSingle):
r = self.rpc.do(o)
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])
r = self.rpc.do(o)
balance = c.parse_balance(r)

View File

@ -9,7 +9,7 @@ contract DemurrageTokenSingleCap {
struct redistributionItem {
uint32 period;
uint72 value;
uint40 demurrage;
uint64 demurrage;
}
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);
// 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
event Burn(address indexed _burner, uint256 _value);
@ -128,9 +129,8 @@ contract DemurrageTokenSingleCap {
periodDuration = _periodMinutes * 60;
demurrageAmount = ABDKMath64x64.fromUInt(1);
//taxLevel = ABDKMath64x64.mul(ABDKMath64x64.ln(ABDKMath64x64.sub(demurrageAmount, , ABDKMath64x64.fromUInt(_periodMinutes));
taxLevel = ABDKMath64x64.ln(_taxLevel);
initialRedistribution = toRedistribution(0, uint40(uint128(demurrageAmount)), 0, 1);
initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution);
// Misc settings
@ -170,8 +170,6 @@ contract DemurrageTokenSingleCap {
currentDemurragedAmount = ABDKMath64x64.mul(baseBalance, demurrageAmount);
return decayBy(ABDKMath64x64.toUInt(currentDemurragedAmount), periodCount);
//return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
}
// Balance unmodified by demurrage
@ -214,10 +212,6 @@ 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) {
@ -235,12 +229,12 @@ contract DemurrageTokenSingleCap {
}
// 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;
redistribution.period = uint32(_period);
redistribution.value = uint72(_value);
redistribution.demurrage = uint40(_demurrageModifierPpm);
redistribution.demurrage = uint64(uint128(_demurrageModifier) & 0xffffffffffffffff);
return redistribution;
}
@ -256,8 +250,14 @@ contract DemurrageTokenSingleCap {
}
// Serializes the number of participants part of the redistribution word
function toRedistributionDemurrageModifier(redistributionItem memory _redistribution) public pure returns (uint256) {
return uint256(_redistribution.demurrage);
function toRedistributionDemurrageModifier(redistributionItem memory _redistribution) public pure returns (int128) {
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);
}
// // Retrieve next redistribution if the period threshold has been crossed
// function checkPeriod() private view returns (redistributionItem memory) {
// redistributionItem memory lastRedistribution;
// redistributionItem memory emptyRedistribution;
// uint256 currentPeriod;
//
// lastRedistribution = redistributions[lastPeriod];
// currentPeriod = this.actualPeriod();
// if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
// return emptyRedistribution;
// }
// return lastRedistribution;
// }
// Retrieve next redistribution if the period threshold has been crossed
function checkPeriod() private view returns (redistributionItem memory) {
redistributionItem memory lastRedistribution;
redistributionItem memory emptyRedistribution;
uint256 currentPeriod;
lastRedistribution = redistributions[lastPeriod];
currentPeriod = this.actualPeriod();
if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
return emptyRedistribution;
}
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));
// return difference / resolutionFactor;
// }
difference = ABDKMath64x64.mul(ABDKMath64x64.fromUInt(_supply), _demurrageAmount);
return ABDKMath64x64.toUInt(difference);
//return _supply;
}
// function getDistributionFromRedistribution(redistributionItem memory _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(redistributionItem memory _redistribution) private returns (uint256) {
// uint256 unit;
// uint256 baseUnit;
//
// unit = getDistributionFromRedistribution(_redistribution);
// baseUnit = toBaseAmount(unit) - totalSink;
// increaseBaseBalance(sinkAddress, baseUnit);
// lastPeriod += 1;
// totalSink += baseUnit;
// return unit;
// }
function getDistributionFromRedistribution(redistributionItem memory _redistribution) public returns (uint256) {
uint256 redistributionSupply;
int128 redistributionDemurrage;
redistributionSupply = toRedistributionSupply(_redistribution);
redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
return getDistribution(redistributionSupply, redistributionDemurrage);
}
// Returns the amount sent to the sink address
function applyDefaultRedistribution(redistributionItem memory _redistribution) private returns (uint256) {
uint256 unit;
uint256 baseUnit;
unit = getDistributionFromRedistribution(_redistribution);
baseUnit = toBaseAmount(unit) - totalSink;
increaseBaseBalance(sinkAddress, baseUnit);
emit Redistribution(sinkAddress, _redistribution.period, unit);
lastPeriod += 1;
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
function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) {
@ -388,53 +427,6 @@ contract DemurrageTokenSingleCap {
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
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {