mirror of
git://holbrook.no/erc20-demurrage-token
synced 2024-11-22 08:16:47 +01:00
Rehabilitate change period
This commit is contained in:
parent
3333d50f98
commit
555b0b1724
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user