Rehabilitate single nocap contract

This commit is contained in:
nolash 2021-06-08 16:38:45 +02:00
parent 606b8d6238
commit 2123341fe9
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 92 additions and 60 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

View File

@ -4,7 +4,8 @@ set -e
export PYTHONPATH=. export PYTHONPATH=.
modes=(MultiNocap MultiCap SingleCap SingleNocap) #modes=(MultiNocap MultiCap SingleCap SingleNocap)
modes=(SingleCap SingleNocap) # other contracts need to be updted
for m in ${modes[@]}; do for m in ${modes[@]}; do
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
@ -22,10 +23,10 @@ for m in ${modes[@]}; do
ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution_unit.py
done 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_remainder.py # ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_remainder.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
set +e set +e

View File

@ -14,10 +14,6 @@ contract DemurrageTokenSingleCap {
uint8 constant shiftRedistributionDemurrage = 104; uint8 constant shiftRedistributionDemurrage = 104;
uint256 constant maskRedistributionDemurrage = 0x000000ffffffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140 uint256 constant maskRedistributionDemurrage = 0x000000ffffffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140
uint8 constant shiftRedistributionIsUsed = 255;
uint256 constant maskRedistributionIsUsed = 0x4000000000000000000000000000000000000000000000000000000000000000; // 1 << 255
// Account balances // Account balances
mapping (address => uint256) account; mapping (address => uint256) account;

View File

@ -2,17 +2,21 @@ pragma solidity > 0.6.11;
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
contract DemurrageTokenSingleNocap { contract DemurrageTokenSingleCap {
// Redistribution bit field, with associated shifts and masks // Redistribution bit field, with associated shifts and masks
// (Uses sub-byte boundaries) // (Uses sub-byte boundaries)
bytes32[] public redistributions; // uint95(unused) | uint20(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period) bytes32[] public redistributions; // uint51(unused) | uint64(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
uint8 constant shiftRedistributionPeriod = 0; uint8 constant shiftRedistributionPeriod = 0;
uint256 constant maskRedistributionPeriod = 0x00000000000000000000000000000000000000000000000000000000ffffffff; // (1 << 32) - 1 uint256 constant maskRedistributionPeriod = 0x00000000000000000000000000000000000000000000000000000000ffffffff; // (1 << 32) - 1
uint8 constant shiftRedistributionValue = 32; uint8 constant shiftRedistributionValue = 32;
uint256 constant maskRedistributionValue = 0x00000000000000000000000000000000000000ffffffffffffffffff00000000; // ((1 << 72) - 1) << 32 uint256 constant maskRedistributionValue = 0x00000000000000000000000000000000000000ffffffffffffffffff00000000; // ((1 << 72) - 1) << 32
uint8 constant shiftRedistributionDemurrage = 140; uint8 constant shiftRedistributionDemurrage = 104;
uint256 constant maskRedistributionDemurrage = 0x000000000000000000000000fffff00000000000000000000000000000000000; // ((1 << 20) - 1) << 140 uint256 constant maskRedistributionDemurrage = 0x000000ffffffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 20) - 1) << 140
uint8 constant shiftRedistributionIsUsed = 255;
uint256 constant maskRedistributionIsUsed = 0x4000000000000000000000000000000000000000000000000000000000000000; // 1 << 255
// Account balances // Account balances
mapping (address => uint256) account; mapping (address => uint256) account;
@ -21,7 +25,9 @@ contract DemurrageTokenSingleNocap {
uint128 public demurrageAmount; uint128 public demurrageAmount;
// Cached demurrage period; the period for which demurrageAmount was calculated // Cached demurrage period; the period for which demurrageAmount was calculated
uint128 public demurragePeriod; //uint128 public demurragePeriod;
// Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
uint256 public demurrageTimestamp;
// Implements EIP172 // Implements EIP172
address public owner; address public owner;
@ -45,7 +51,13 @@ contract DemurrageTokenSingleNocap {
// 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)
uint256 constant ppmDivider = 100000000000000000000000000000000; uint256 constant nanoDivider = 100000000000000000000000000; // now nanodivider, 6 zeros less
// remaining decimal positions of nanoDivider to reach 38, equals precision in growth and decay
uint256 constant growthResolutionFactor = 1000000000000;
// demurrage decimal width; 38 places
uint256 immutable resolutionFactor = nanoDivider * growthResolutionFactor;
// Timestamp of start of periods (time which contract constructor was called) // Timestamp of start of periods (time which contract constructor was called)
uint256 public immutable periodStart; uint256 public immutable periodStart;
@ -89,7 +101,7 @@ contract DemurrageTokenSingleNocap {
// EIP173 // EIP173
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress) public { constructor(string memory _name, string memory _symbol, uint8 _decimals, uint128 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress) public {
// ACL setup // ACL setup
owner = msg.sender; owner = msg.sender;
minter[owner] = true; minter[owner] = true;
@ -100,12 +112,14 @@ contract DemurrageTokenSingleNocap {
decimals = _decimals; decimals = _decimals;
// Demurrage setup // Demurrage setup
periodStart = block.timestamp; demurrageTimestamp = block.timestamp;
periodStart = demurrageTimestamp;
periodDuration = _periodMinutes * 60; periodDuration = _periodMinutes * 60;
demurrageAmount = uint128(ppmDivider * 1000000); // Represents 38 decimal places //demurrageAmount = 100000000000000000000000000000000000000 - _taxLevelMinute; // Represents 38 decimal places, same as resolutionFactor
demurragePeriod = 1; demurrageAmount = 100000000000000000000000000000000000000;
//demurragePeriod = 1;
taxLevel = _taxLevelMinute; // Represents 38 decimal places taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, 1000000, 0, 1); bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution); redistributions.push(initialRedistribution);
// Misc settings // Misc settings
@ -135,11 +149,12 @@ contract DemurrageTokenSingleNocap {
baseBalance = baseBalanceOf(_account); baseBalance = baseBalanceOf(_account);
periodCount = actualPeriod() - demurragePeriod; //periodCount = actualPeriod() - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp);
currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount)); currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount));
return (baseBalance * currentDemurragedAmount) / (ppmDivider * 1000000); return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
} }
/// Balance unmodified by demurrage /// Balance unmodified by demurrage
@ -187,10 +202,10 @@ contract DemurrageTokenSingleNocap {
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');
changePeriod(); changePeriod();
baseAmount = _amount; baseAmount = toBaseAmount(_amount);
totalSupply += _amount; totalSupply += _amount;
increaseBaseBalance(_beneficiary, baseAmount); increaseBaseBalance(_beneficiary, baseAmount);
emit Mint(msg.sender, _beneficiary, _amount); emit Mint(msg.sender, _beneficiary, _amount);
@ -200,7 +215,7 @@ contract DemurrageTokenSingleNocap {
// Deserializes the redistribution word // Deserializes the redistribution word
// uint95(unused) | uint20(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period) // uint95(unused) | uint20(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) private pure returns(bytes32) { function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) public pure returns(bytes32) {
bytes32 redistribution; bytes32 redistribution;
redistribution |= bytes32((_demurrageModifierPpm << shiftRedistributionDemurrage) & maskRedistributionDemurrage); redistribution |= bytes32((_demurrageModifierPpm << shiftRedistributionDemurrage) & maskRedistributionDemurrage);
@ -232,10 +247,13 @@ contract DemurrageTokenSingleNocap {
// Save the current total supply amount to the current redistribution period // Save the current total supply amount to the current redistribution period
function saveRedistributionSupply() private returns (bool) { function saveRedistributionSupply() private returns (bool) {
uint256 currentRedistribution; uint256 currentRedistribution;
uint256 grownSupply;
//grownSupply = growBy(totalSupply, 1);
grownSupply = totalSupply;
currentRedistribution = uint256(redistributions[redistributions.length-1]); currentRedistribution = uint256(redistributions[redistributions.length-1]);
currentRedistribution &= (~maskRedistributionValue); currentRedistribution &= (~maskRedistributionValue);
currentRedistribution |= (totalSupply << shiftRedistributionValue); currentRedistribution |= (grownSupply << shiftRedistributionValue);
redistributions[redistributions.length-1] = bytes32(currentRedistribution); redistributions[redistributions.length-1] = bytes32(currentRedistribution);
return true; return true;
@ -259,35 +277,54 @@ contract DemurrageTokenSingleNocap {
return lastRedistribution; return lastRedistribution;
} }
// Returns the amount sent to the sink address function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) { uint256 difference;
difference = _supply * (resolutionFactor - _demurrageAmount); //(nanoDivider - ((resolutionFactor - _demurrageAmount) / nanoDivider));
return difference / resolutionFactor;
}
function getDistributionFromRedistribution(bytes32 _redistribution) public returns (uint256) {
uint256 redistributionSupply; uint256 redistributionSupply;
uint256 unit; uint256 redistributionDemurrage;
redistributionSupply = toRedistributionSupply(_redistribution); redistributionSupply = toRedistributionSupply(_redistribution);
redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
return getDistribution(redistributionSupply, redistributionDemurrage);
}
unit = (redistributionSupply * taxLevel) / 1000000; // Returns the amount sent to the sink address
function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) {
uint256 unit;
increaseBaseBalance(sinkAddress, unit / ppmDivider); unit = getDistributionFromRedistribution(_redistribution);
increaseBaseBalance(sinkAddress, toBaseAmount(unit));
return unit; return unit;
} }
// Calculate the time delta in whole minutes passed between given timestamp and current timestamp
function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) {
return (block.timestamp - _lastTimestamp) / 60;
}
// 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;
uint128 periodCount; uint256 periodCount;
uint256 lastDemurrageAmount; uint256 lastDemurrageAmount;
uint256 newDemurrageAmount;
epochPeriodCount = actualPeriod(); //epochPeriodCount = actualPeriod();
periodCount = epochPeriodCount - demurragePeriod; //periodCount = epochPeriodCount - demurragePeriod;
periodCount = getMinutesDelta(demurrageTimestamp);
if (periodCount == 0) { if (periodCount == 0) {
return false; return false;
} }
lastDemurrageAmount = demurrageAmount; lastDemurrageAmount = demurrageAmount;
demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount)); demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
demurragePeriod = epochPeriodCount; //demurragePeriod = epochPeriodCount;
emit Decayed(epochPeriodCount, periodCount, lastDemurrageAmount, demurrageAmount); demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
return true; return true;
} }
@ -312,6 +349,7 @@ contract DemurrageTokenSingleNocap {
uint256 periodTimestamp; uint256 periodTimestamp;
uint256 nextPeriod; uint256 nextPeriod;
applyDemurrage();
currentRedistribution = checkPeriod(); currentRedistribution = checkPeriod();
if (currentRedistribution == bytes32(0x00)) { if (currentRedistribution == bytes32(0x00)) {
return false; return false;
@ -321,20 +359,19 @@ contract DemurrageTokenSingleNocap {
nextPeriod = currentPeriod + 1; nextPeriod = currentPeriod + 1;
periodTimestamp = getPeriodTimeDelta(currentPeriod); periodTimestamp = getPeriodTimeDelta(currentPeriod);
applyDemurrage();
currentDemurrageAmount = demurrageAmount; currentDemurrageAmount = demurrageAmount;
demurrageCounts = demurrageCycles(periodTimestamp); demurrageCounts = demurrageCycles(periodTimestamp);
if (demurrageCounts > 0) { if (demurrageCounts > 0) {
nextRedistributionDemurrage = growBy(currentDemurrageAmount, demurrageCounts) / ppmDivider; nextRedistributionDemurrage = growBy(currentDemurrageAmount, demurrageCounts);
} else { } else {
nextRedistributionDemurrage = currentDemurrageAmount / ppmDivider; nextRedistributionDemurrage = currentDemurrageAmount;
} }
nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod); nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod);
redistributions.push(nextRedistribution); redistributions.push(nextRedistribution);
applyDefaultRedistribution(currentRedistribution); applyDefaultRedistribution(nextRedistribution);
emit Period(nextPeriod); emit Period(nextPeriod);
return true; return true;
} }
@ -344,33 +381,32 @@ contract DemurrageTokenSingleNocap {
uint256 valueFactor; uint256 valueFactor;
uint256 truncatedTaxLevel; uint256 truncatedTaxLevel;
valueFactor = 1000000; valueFactor = growthResolutionFactor;
truncatedTaxLevel = taxLevel / ppmDivider; truncatedTaxLevel = taxLevel / nanoDivider;
for (uint256 i = 0; i < _period; i++) { for (uint256 i = 0; i < _period; i++) {
valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / 1000000); valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
} }
return (valueFactor * _value) / 1000000; return (valueFactor * _value) / growthResolutionFactor;
} }
// Calculate a value reduced by demurrage by the given period // Calculate a value reduced by demurrage by the given period
// TODO: higher precision if possible
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) { function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {
uint256 valueFactor; uint256 valueFactor;
uint256 truncatedTaxLevel; uint256 truncatedTaxLevel;
valueFactor = 1000000; valueFactor = growthResolutionFactor;
truncatedTaxLevel = taxLevel / ppmDivider; truncatedTaxLevel = taxLevel / nanoDivider;
for (uint256 i = 0; i < _period; i++) { for (uint256 i = 0; i < _period; i++) {
valueFactor = valueFactor - ((valueFactor * truncatedTaxLevel) / 1000000); valueFactor = valueFactor - ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
} }
return (valueFactor * _value) / 1000000; return (valueFactor * _value) / growthResolutionFactor;
} }
// 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 * resolutionFactor) / demurrageAmount;
} }
// Implements ERC20, triggers tax and/or redistribution // Implements ERC20, triggers tax and/or redistribution
@ -398,7 +434,6 @@ contract DemurrageTokenSingleNocap {
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;
@ -421,7 +456,7 @@ contract DemurrageTokenSingleNocap {
decreaseBaseBalance(_from, _value); decreaseBaseBalance(_from, _value);
increaseBaseBalance(_to, _value); increaseBaseBalance(_to, _value);
period = actualPeriod(); //period = actualPeriod();
return true; return true;
} }