Remove complex account period tracker in single mode

This commit is contained in:
nolash 2021-06-05 12:39:53 +02:00
parent f338510a1d
commit 74ef57a6a7
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
7 changed files with 19 additions and 180 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,6 @@ export PYTHONPATH=.
modes=(MultiNocap MultiCap SingleCap SingleNocap) modes=(MultiNocap MultiCap SingleCap SingleNocap)
for m in ${modes[@]}; do for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_pure.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_basic.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_basic.py
done done
@ -23,6 +22,7 @@ done
modes=(MultiCap MultiNocap) modes=(MultiCap MultiNocap)
for m in ${modes[@]}; do for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_pure.py
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution.py
done done

View File

@ -18,13 +18,8 @@ contract DemurrageTokenSingleCap {
uint8 constant shiftRedistributionIsFractional = 255; uint8 constant shiftRedistributionIsFractional = 255;
uint256 constant maskRedistributionIsFractional = 0x8000000000000000000000000000000000000000000000000000000000000000; // 1 << 255 uint256 constant maskRedistributionIsFractional = 0x8000000000000000000000000000000000000000000000000000000000000000; // 1 << 255
// Account bit field, with associated shifts and masks // Account balances
// Mirrors structure of redistributions for consistency mapping (address => uint256) account;
mapping (address => bytes32) account; // uint152(unused) | uint32(period) | uint72(value)
uint8 constant shiftAccountValue = 0;
uint256 constant maskAccountValue = 0x0000000000000000000000000000000000000000000000ffffffffffffffffff; // (1 << 72) - 1
uint8 constant shiftAccountPeriod = 72;
uint256 constant maskAccountPeriod = 0x00000000000000000000000000000000000000ffffffff000000000000000000; // ((1 << 32) - 1) << 72
// Cached demurrage amount, ppm with 38 digit resolution // Cached demurrage amount, ppm with 38 digit resolution
uint128 public demurrageAmount; uint128 public demurrageAmount;
@ -157,7 +152,7 @@ contract DemurrageTokenSingleCap {
/// Balance unmodified by demurrage /// Balance unmodified by demurrage
function baseBalanceOf(address _account) public view returns (uint256) { function baseBalanceOf(address _account) public view returns (uint256) {
return uint256(account[_account]) & maskAccountValue; return account[_account];
} }
/// Increases base balance for a single account /// Increases base balance for a single account
@ -173,11 +168,7 @@ contract DemurrageTokenSingleCap {
} }
oldBalance = baseBalanceOf(_account); oldBalance = baseBalanceOf(_account);
newBalance = oldBalance + _delta; account[_account] = oldBalance + _delta;
require(uint160(newBalance) > uint160(oldBalance), 'ERR_WOULDWRAP'); // revert if increase would result in a wrapped value
workAccount &= (~maskAccountValue);
workAccount |= (newBalance & maskAccountValue);
account[_account] = bytes32(workAccount);
return true; return true;
} }
@ -195,10 +186,7 @@ contract DemurrageTokenSingleCap {
oldBalance = baseBalanceOf(_account); oldBalance = baseBalanceOf(_account);
require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard
newBalance = oldBalance - _delta; account[_account] = oldBalance - _delta;
workAccount &= (~maskAccountValue);
workAccount |= (newBalance & maskAccountValue);
account[_account] = bytes32(workAccount);
return true; return true;
} }
@ -207,8 +195,8 @@ contract DemurrageTokenSingleCap {
function mintTo(address _beneficiary, uint256 _amount) external returns (bool) { function mintTo(address _beneficiary, uint256 _amount) external returns (bool) {
uint256 baseAmount; uint256 baseAmount;
require(minter[msg.sender]); require(minter[msg.sender], 'ERR_ACCESS');
require(_amount + totalSupply <= supplyCap); require(_amount + totalSupply <= supplyCap, 'ERR_CAP');
changePeriod(); changePeriod();
baseAmount = _amount; baseAmount = _amount;
@ -303,36 +291,6 @@ contract DemurrageTokenSingleCap {
return lastRedistribution; return lastRedistribution;
} }
// Deserialize the pemurrage period for the given account is participating in
function accountPeriod(address _account) public view returns (uint256) {
return (uint256(account[_account]) & maskAccountPeriod) >> shiftAccountPeriod;
}
// Save the given demurrage period as the currently participation period for the given address
function registerAccountPeriod(address _account, uint256 _period) private returns (bool) {
account[_account] &= bytes32(~maskAccountPeriod);
account[_account] |= bytes32((_period << shiftAccountPeriod) & maskAccountPeriod);
incrementRedistributionParticipants();
return true;
}
// Determine whether the unit number is rounded down, rounded up or evenly divides.
// Returns 0 if evenly distributed, or the remainder as a positive number
// A _numParts value 0 will be interpreted as the value 1
function remainder(uint256 _numParts, uint256 _sumWhole) public pure returns (uint256) {
uint256 unit;
uint256 truncatedResult;
if (_numParts == 0) { // no division by zero please
revert('ERR_NUMPARTS_ZERO');
}
require(_numParts < _sumWhole); // At least you are never LESS than the sum of your parts. Think about that.
unit = _sumWhole / _numParts;
truncatedResult = unit * _numParts;
return _sumWhole - truncatedResult;
}
// Returns the amount sent to the sink address // Returns the amount sent to the sink address
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) { function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
uint256 redistributionSupply; uint256 redistributionSupply;
@ -355,24 +313,6 @@ contract DemurrageTokenSingleCap {
return unit; return unit;
} }
// sets the remainder bit for the given period and books the remainder to the sink address balance
// returns false if no change was made
function applyRemainderOnPeriod(uint256 _remainder, uint256 _period) private returns (bool) {
uint256 periodSupply;
if (_remainder == 0) {
return false;
}
// TODO: is this needed?
redistributions[_period-1] |= bytes32(maskRedistributionIsFractional);
periodSupply = toRedistributionSupply(redistributions[_period-1]);
increaseBaseBalance(sinkAddress, periodSupply - _remainder);
return true;
}
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call // Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
function applyDemurrage() public returns (bool) { function applyDemurrage() public returns (bool) {
uint128 epochPeriodCount; uint128 epochPeriodCount;
@ -408,7 +348,6 @@ contract DemurrageTokenSingleCap {
bytes32 nextRedistribution; bytes32 nextRedistribution;
uint256 currentPeriod; uint256 currentPeriod;
uint256 currentParticipants; uint256 currentParticipants;
uint256 currentRemainder;
uint256 currentDemurrageAmount; uint256 currentDemurrageAmount;
uint256 nextRedistributionDemurrage; uint256 nextRedistributionDemurrage;
uint256 demurrageCounts; uint256 demurrageCounts;
@ -437,7 +376,7 @@ contract DemurrageTokenSingleCap {
nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod); nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod);
redistributions.push(nextRedistribution); redistributions.push(nextRedistribution);
currentRemainder = applyDefaultRedistribution(currentRedistribution); applyDefaultRedistribution(currentRedistribution);
emit Period(nextPeriod); emit Period(nextPeriod);
return true; return true;
} }
@ -471,22 +410,6 @@ contract DemurrageTokenSingleCap {
return (valueFactor * _value) / 1000000; return (valueFactor * _value) / 1000000;
} }
// If the given account is participating in a period and that period has been crossed
// THEN increase the base value of the account with its share of the value reduction of the period
function applyRedistributionOnAccount(address _account) public returns (bool) {
uint256 period;
period = accountPeriod(_account);
if (period == 0 || period >= actualPeriod()) {
return false;
}
// zero out period for the account
account[_account] &= bytes32(~maskAccountPeriod);
return true;
}
// 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 * ppmDivider * 1000000) / demurrageAmount; return (_value * ppmDivider * 1000000) / demurrageAmount;
@ -517,7 +440,6 @@ contract DemurrageTokenSingleCap {
return result; return result;
} }
// Implements ERC20, triggers tax and/or redistribution // Implements ERC20, triggers tax and/or redistribution
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
uint256 baseValue; uint256 baseValue;
@ -541,9 +463,6 @@ contract DemurrageTokenSingleCap {
increaseBaseBalance(_to, _value); increaseBaseBalance(_to, _value);
period = actualPeriod(); period = actualPeriod();
if (_value >= minimumParticipantSpend && accountPeriod(_from) != period && _from != _to) {
registerAccountPeriod(_from, period);
}
return true; return true;
} }

View File

@ -18,13 +18,8 @@ contract DemurrageTokenSingleNocap {
uint8 constant shiftRedistributionIsFractional = 255; uint8 constant shiftRedistributionIsFractional = 255;
uint256 constant maskRedistributionIsFractional = 0x8000000000000000000000000000000000000000000000000000000000000000; // 1 << 255 uint256 constant maskRedistributionIsFractional = 0x8000000000000000000000000000000000000000000000000000000000000000; // 1 << 255
// Account bit field, with associated shifts and masks // Account balances
// Mirrors structure of redistributions for consistency mapping (address => uint256) account;
mapping (address => bytes32) account; // uint152(unused) | uint32(period) | uint72(value)
uint8 constant shiftAccountValue = 0;
uint256 constant maskAccountValue = 0x0000000000000000000000000000000000000000000000ffffffffffffffffff; // (1 << 72) - 1
uint8 constant shiftAccountPeriod = 72;
uint256 constant maskAccountPeriod = 0x00000000000000000000000000000000000000ffffffff000000000000000000; // ((1 << 32) - 1) << 72
// Cached demurrage amount, ppm with 38 digit resolution // Cached demurrage amount, ppm with 38 digit resolution
uint128 public demurrageAmount; uint128 public demurrageAmount;
@ -153,7 +148,7 @@ contract DemurrageTokenSingleNocap {
/// Balance unmodified by demurrage /// Balance unmodified by demurrage
function baseBalanceOf(address _account) public view returns (uint256) { function baseBalanceOf(address _account) public view returns (uint256) {
return uint256(account[_account]) & maskAccountValue; return account[_account];
} }
/// Increases base balance for a single account /// Increases base balance for a single account
@ -169,11 +164,7 @@ contract DemurrageTokenSingleNocap {
} }
oldBalance = baseBalanceOf(_account); oldBalance = baseBalanceOf(_account);
newBalance = oldBalance + _delta; account[_account] = oldBalance + _delta;
require(uint160(newBalance) > uint160(oldBalance), 'ERR_WOULDWRAP'); // revert if increase would result in a wrapped value
workAccount &= (~maskAccountValue);
workAccount |= (newBalance & maskAccountValue);
account[_account] = bytes32(workAccount);
return true; return true;
} }
@ -191,10 +182,7 @@ contract DemurrageTokenSingleNocap {
oldBalance = baseBalanceOf(_account); oldBalance = baseBalanceOf(_account);
require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard
newBalance = oldBalance - _delta; account[_account] = oldBalance - _delta;
workAccount &= (~maskAccountValue);
workAccount |= (newBalance & maskAccountValue);
account[_account] = bytes32(workAccount);
return true; return true;
} }
@ -298,36 +286,6 @@ contract DemurrageTokenSingleNocap {
return lastRedistribution; return lastRedistribution;
} }
// Deserialize the pemurrage period for the given account is participating in
function accountPeriod(address _account) public view returns (uint256) {
return (uint256(account[_account]) & maskAccountPeriod) >> shiftAccountPeriod;
}
// Save the given demurrage period as the currently participation period for the given address
function registerAccountPeriod(address _account, uint256 _period) private returns (bool) {
account[_account] &= bytes32(~maskAccountPeriod);
account[_account] |= bytes32((_period << shiftAccountPeriod) & maskAccountPeriod);
incrementRedistributionParticipants();
return true;
}
// Determine whether the unit number is rounded down, rounded up or evenly divides.
// Returns 0 if evenly distributed, or the remainder as a positive number
// A _numParts value 0 will be interpreted as the value 1
function remainder(uint256 _numParts, uint256 _sumWhole) public pure returns (uint256) {
uint256 unit;
uint256 truncatedResult;
if (_numParts == 0) { // no division by zero please
revert('ERR_NUMPARTS_ZERO');
}
require(_numParts < _sumWhole); // At least you are never LESS than the sum of your parts. Think about that.
unit = _sumWhole / _numParts;
truncatedResult = unit * _numParts;
return _sumWhole - truncatedResult;
}
// Returns the amount sent to the sink address // Returns the amount sent to the sink address
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) { function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
uint256 redistributionSupply; uint256 redistributionSupply;
@ -350,24 +308,6 @@ contract DemurrageTokenSingleNocap {
return unit; return unit;
} }
// sets the remainder bit for the given period and books the remainder to the sink address balance
// returns false if no change was made
function applyRemainderOnPeriod(uint256 _remainder, uint256 _period) private returns (bool) {
uint256 periodSupply;
if (_remainder == 0) {
return false;
}
// TODO: is this needed?
redistributions[_period-1] |= bytes32(maskRedistributionIsFractional);
periodSupply = toRedistributionSupply(redistributions[_period-1]);
increaseBaseBalance(sinkAddress, periodSupply - _remainder);
return true;
}
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call // Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
function applyDemurrage() public returns (bool) { function applyDemurrage() public returns (bool) {
uint128 epochPeriodCount; uint128 epochPeriodCount;
@ -403,7 +343,6 @@ contract DemurrageTokenSingleNocap {
bytes32 nextRedistribution; bytes32 nextRedistribution;
uint256 currentPeriod; uint256 currentPeriod;
uint256 currentParticipants; uint256 currentParticipants;
uint256 currentRemainder;
uint256 currentDemurrageAmount; uint256 currentDemurrageAmount;
uint256 nextRedistributionDemurrage; uint256 nextRedistributionDemurrage;
uint256 demurrageCounts; uint256 demurrageCounts;
@ -432,7 +371,7 @@ contract DemurrageTokenSingleNocap {
nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod); nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod);
redistributions.push(nextRedistribution); redistributions.push(nextRedistribution);
currentRemainder = applyDefaultRedistribution(currentRedistribution); applyDefaultRedistribution(currentRedistribution);
emit Period(nextPeriod); emit Period(nextPeriod);
return true; return true;
} }
@ -466,24 +405,8 @@ contract DemurrageTokenSingleNocap {
return (valueFactor * _value) / 1000000; return (valueFactor * _value) / 1000000;
} }
// If the given account is participating in a period and that period has been crossed
// THEN increase the base value of the account with its share of the value reduction of the period
function applyRedistributionOnAccount(address _account) public returns (bool) {
uint256 period;
period = accountPeriod(_account);
if (period == 0 || period >= actualPeriod()) {
return false;
}
// zero out period for the account
account[_account] &= bytes32(~maskAccountPeriod);
return true;
}
// 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 * ppmDivider * 1000000) / toDemurrageAmount(demurrageModifier);
return (_value * ppmDivider * 1000000) / demurrageAmount; return (_value * ppmDivider * 1000000) / demurrageAmount;
} }
@ -536,9 +459,6 @@ contract DemurrageTokenSingleNocap {
increaseBaseBalance(_to, _value); increaseBaseBalance(_to, _value);
period = actualPeriod(); period = actualPeriod();
if (_value >= minimumParticipantSpend && accountPeriod(_from) != period && _from != _to) {
registerAccountPeriod(_from, period);
}
return true; return true;
} }