1 Commits

Author SHA1 Message Date
lash
db2acc3109 WIP reintroduce multi contract code for storing snapshot 2023-01-18 08:30:51 +00:00
4 changed files with 124 additions and 69 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

@@ -90,6 +90,7 @@ class TestRedistributionSingle(TestDemurrageSingle):
r = self.rpc.do(o)
balance = c.parse_balance(r)
expected_balance = new_supply - (new_supply * tax_modifier)
logg.debug('expected balance {}'.format(expected_balance))
self.assert_within_lower(balance, expected_balance, 1)

View File

@@ -10,17 +10,24 @@ contract DemurrageTokenSingleCap {
uint256 constant maskRedistributionPeriod = 0x00000000000000000000000000000000000000000000000000000000ffffffff; // (1 << 32) - 1
uint8 constant shiftRedistributionValue = 32;
uint256 constant maskRedistributionValue = 0x00000000000000000000000000000000000000ffffffffffffffffff00000000; // ((1 << 72) - 1) << 32
uint8 constant shiftRedistributionDemurrage = 104;
uint256 constant maskRedistributionDemurrage = 0x0000000000ffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 36) - 1) << 140
uint8 constant shiftRedistributionParticipants = 104;
uint256 constant maskRedistributionParticipants = 0x00000000000000000000000000000fffffffff00000000000000000000000000; // ((1 << 36) - 1) << 104
uint8 constant shiftRedistributionDemurrage = 140;
uint256 constant maskRedistributionDemurrage = 0x000000000000000000000000fffff00000000000000000000000000000000000; // ((1 << 20) - 1) << 140
// Account balances
mapping (address => bytes32[] ) account;
//uint8 constant shiftRedistributionDemurrage = 104;
//uint256 constant maskRedistributionDemurrage = 0x0000000000ffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 36) - 1) << 140
// Account bit field, with associated shifts and masks
// Mirrors structure of redistributions for consistency
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
uint8 constant shiftAccountUsed = 255;
uint256 constant maskAccountUsed = 0x8000000000000000000000000000000000000000000000000000000000000000; // (1 << 255)
// Account balances
//mapping (address => uint256) account;
// Cached demurrage amount, ppm with 38 digit resolution
uint128 public demurrageAmount;
@@ -154,6 +161,36 @@ contract DemurrageTokenSingleCap {
return true;
}
// 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;
}
// Add number of participants for the current redistribution period by one
function incrementRedistributionParticipants() private returns (bool) {
bytes32 currentRedistribution;
uint256 tmpRedistribution;
uint256 participants;
currentRedistribution = redistributions[redistributions.length-1];
participants = toRedistributionParticipants(currentRedistribution) + 1;
tmpRedistribution = uint256(currentRedistribution);
tmpRedistribution &= (~maskRedistributionParticipants);
tmpRedistribution |= ((participants << shiftRedistributionParticipants) & maskRedistributionParticipants);
redistributions[redistributions.length-1] = bytes32(tmpRedistribution);
return true;
}
// 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;
}
/// Implements ERC20
function balanceOf(address _account) public view returns (uint256) {
uint256 baseBalance;
@@ -169,39 +206,94 @@ contract DemurrageTokenSingleCap {
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
}
/// Balance unmodified by demurrage
function baseBalanceOf(address _account) public view returns (uint256) {
uint256 lastPeriodUsed;
lastPeriodUsed = account[_account].length;
if (lastPeriodUsed == 0) {
return 0;
}
return uint256(account[_account][lastPeriodUsed]) & maskAccountValue;
return uint256(account[_account]) & maskAccountValue;
}
/// Increases base balance for a single account
function increaseBaseBalance(address _account, uint256 _delta) private returns (bool) {
uint256 oldBalance;
uint256 newBalance;
uint256 workAccount;
workAccount = uint256(account[_account]);
if (_delta == 0) {
return false;
}
movePeriodBalance(_account, int256(_delta));
oldBalance = baseBalanceOf(_account);
newBalance = 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;
}
/// Decreases base balance for a single account
function decreaseBaseBalance(address _account, uint256 _delta) private returns (bool) {
uint256 oldBalance;
uint256 newBalance;
uint256 workAccount;
workAccount = uint256(account[_account]);
if (_delta == 0) {
return false;
}
movePeriodBalance(_account, int256(_delta) * -1);
oldBalance = baseBalanceOf(_account);
require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard
newBalance = oldBalance - _delta;
workAccount &= (~maskAccountValue);
workAccount |= (newBalance & maskAccountValue);
account[_account] = bytes32(workAccount);
return true;
}
// /// Balance unmodified by demurrage
// function baseBalanceOf(address _account) public view returns (uint256) {
// return account[_account];
// }
//
// /// Increases base balance for a single account
// function increaseBaseBalance(address _account, uint256 _delta) private returns (bool) {
// uint256 oldBalance;
// uint256 newBalance;
// uint256 workAccount;
//
// workAccount = uint256(account[_account]);
//
// if (_delta == 0) {
// return false;
// }
//
// oldBalance = baseBalanceOf(_account);
// account[_account] = oldBalance + _delta;
// return true;
// }
//
// /// Decreases base balance for a single account
// function decreaseBaseBalance(address _account, uint256 _delta) private returns (bool) {
// uint256 oldBalance;
// uint256 newBalance;
// uint256 workAccount;
//
// workAccount = uint256(account[_account]);
//
// if (_delta == 0) {
// return false;
// }
//
// oldBalance = baseBalanceOf(_account);
// require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard
// account[_account] = oldBalance - _delta;
// return true;
// }
// 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) {
@@ -244,6 +336,11 @@ contract DemurrageTokenSingleCap {
return (uint256(redistribution) & maskRedistributionDemurrage) >> shiftRedistributionDemurrage;
}
// Serializes the number of participants part of the redistribution word
function toRedistributionParticipants(bytes32 redistribution) public pure returns (uint256) {
return (uint256(redistribution) & maskRedistributionParticipants) >> shiftRedistributionParticipants;
}
// Client accessor to the redistributions array length
function redistributionCount() public view returns (uint256) {
return redistributions.length;
@@ -307,6 +404,7 @@ contract DemurrageTokenSingleCap {
increaseBaseBalance(sinkAddress, baseUnit);
lastPeriod += 1;
totalSink += baseUnit;
registerAccountPeriod(sinkAddress, lastPeriod);
return unit;
}
@@ -353,54 +451,6 @@ contract DemurrageTokenSingleCap {
return (block.timestamp - _target) / 60;
}
// Deserialize the pemurrage period for the given account is participating in
function accountPeriod(address _account) public view returns (uint256) {
uint256 accountPeriods;
accountPeriods = account[_account].length;
if (accountPeriods == 0) {
return 0;
}
return accountPeriodBase(_account, accountPeriods - 1);
}
function accountPeriodBase(address _account, uint256 _idx) private view returns (uint256) {
return (uint256(account[_account][_idx]) & maskAccountPeriod) >> shiftAccountPeriod;
}
function movePeriodBalance(address _account, int256 _delta) private {
int256 oldBalance;
uint256 newBalance;
uint256 workAccount;
//workAccount = uint256(account[_index][_account]);
oldBalance = int256(baseBalanceOf(_account));
newBalance = uint256(oldBalance + _delta);
require(uint72(newBalance) > uint72(uint256(oldBalance)), 'ERR_WOULDWRAP'); // revert if increase would result in a wrapped value
workAccount = (1 << 255);
workAccount |= ((uint32(lastPeriod) << shiftAccountPeriod) & maskAccountPeriod);
workAccount |= (baseBalanceOf(_account) & maskAccountValue);
account[_account].push(bytes32(workAccount));
}
function registerAccountPeriod(address _account, int256 _delta) public {
uint256 accountPeriods;
uint256 lastPeriodUsed;
accountPeriods = account[_account].length;
if (lastPeriodUsed == 0) {
account[_account].push(bytes32(uint256(_delta) | (1 << 255)));
return;
}
lastPeriodUsed = accountPeriodBase(_account, accountPeriods - 1);
if (lastPeriodUsed != lastPeriod) {
movePeriodBalance(_account, _delta);
}
}
// 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) {
@@ -547,6 +597,10 @@ contract DemurrageTokenSingleCap {
decreaseBaseBalance(_from, _value);
increaseBaseBalance(_to, _value);
period = actualPeriod();
if (accountPeriod(_from) != period && _from != _to) {
registerAccountPeriod(_from, period);
}
return true;
}
@@ -572,7 +626,7 @@ contract DemurrageTokenSingleCap {
// Only token minters can burn tokens
function burn(uint256 _value) public {
require(minter[msg.sender]);
require(_value <= balanceOf(msg.sender));
//require(_value <= account[msg.sender]);
uint256 _delta = toBaseAmount(_value);
applyDemurrage();