Move bitfields to struct

This commit is contained in:
lash 2023-02-08 08:26:15 +00:00
parent 00f4ddba68
commit 7b6a88c889
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 172 additions and 96 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

@ -310,8 +310,11 @@ class DemurrageToken(ERC20):
o['method'] = 'eth_call' o['method'] = 'eth_call'
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('toRedistributionPeriod') enc.method('toRedistributionPeriod')
enc.typ(ABIContractType.BYTES32) v = strip_0x(redistribution)
enc.bytes32(redistribution) enc.typ_literal('(uint32,uint72,uint104)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
data = add_0x(enc.get()) data = add_0x(enc.get())
tx = self.template(sender_address, contract_address) tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data) tx = self.set_code(tx, data)
@ -321,22 +324,26 @@ class DemurrageToken(ERC20):
return o return o
def to_redistribution_participants(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None): # def to_redistribution_participants(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator) # j = JSONRPCRequest(id_generator)
o = j.template() # o = j.template()
o['method'] = 'eth_call' # o['method'] = 'eth_call'
enc = ABIContractEncoder() # enc = ABIContractEncoder()
enc.method('toRedistributionParticipants') # enc.method('toRedistributionParticipants')
enc.typ(ABIContractType.BYTES32) # v = strip_0x(redistribution)
enc.bytes32(redistribution) # enc.typ_literal('(uint32,uint72,uint104)')
data = add_0x(enc.get()) # #enc.typ(ABIContractType.BYTES32)
tx = self.template(sender_address, contract_address) # enc.bytes32(v[:64])
tx = self.set_code(tx, data) # enc.bytes32(v[64:128])
o['params'].append(self.normalize(tx)) # enc.bytes32(v[128:192])
o['params'].append('latest') # data = add_0x(enc.get())
o = j.finalize(o) # tx = self.template(sender_address, contract_address)
return o # tx = self.set_code(tx, data)
# o['params'].append(self.normalize(tx))
# o['params'].append('latest')
# o = j.finalize(o)
# return o
#
def to_redistribution_supply(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None): def to_redistribution_supply(self, contract_address, redistribution, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator) j = JSONRPCRequest(id_generator)
@ -344,8 +351,11 @@ class DemurrageToken(ERC20):
o['method'] = 'eth_call' o['method'] = 'eth_call'
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('toRedistributionSupply') enc.method('toRedistributionSupply')
enc.typ(ABIContractType.BYTES32) v = strip_0x(redistribution)
enc.bytes32(redistribution) enc.typ_literal('(uint32,uint72,uint104)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
data = add_0x(enc.get()) data = add_0x(enc.get())
tx = self.template(sender_address, contract_address) tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data) tx = self.set_code(tx, data)
@ -361,8 +371,11 @@ class DemurrageToken(ERC20):
o['method'] = 'eth_call' o['method'] = 'eth_call'
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('toRedistributionDemurrageModifier') enc.method('toRedistributionDemurrageModifier')
enc.typ(ABIContractType.BYTES32) v = strip_0x(redistribution)
enc.bytes32(redistribution) enc.typ_literal('(uint32,uint72,uint104)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
data = add_0x(enc.get()) data = add_0x(enc.get())
tx = self.template(sender_address, contract_address) tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data) tx = self.set_code(tx, data)
@ -452,24 +465,24 @@ class DemurrageToken(ERC20):
return self.call_noarg('supplyCap', contract_address, sender_address=sender_address) return self.call_noarg('supplyCap', contract_address, sender_address=sender_address)
def grow_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS, id_generator=None): # def grow_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator) # j = JSONRPCRequest(id_generator)
o = j.template() # o = j.template()
o['method'] = 'eth_call' # o['method'] = 'eth_call'
enc = ABIContractEncoder() # enc = ABIContractEncoder()
enc.method('growBy') # enc.method('growBy')
enc.typ(ABIContractType.UINT256) # enc.typ(ABIContractType.UINT256)
enc.typ(ABIContractType.UINT256) # enc.typ(ABIContractType.UINT256)
enc.uint256(value) # enc.uint256(value)
enc.uint256(period) # enc.uint256(period)
data = add_0x(enc.get()) # data = add_0x(enc.get())
tx = self.template(sender_address, contract_address) # tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data) # tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx)) # o['params'].append(self.normalize(tx))
o['params'].append('latest') # o['params'].append('latest')
o = j.finalize(o) # o = j.finalize(o)
return o # return o
#
def decay_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS, id_generator=None): def decay_by(self, contract_address, value, period, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator) j = JSONRPCRequest(id_generator)
@ -515,8 +528,11 @@ class DemurrageToken(ERC20):
o['method'] = 'eth_call' o['method'] = 'eth_call'
enc = ABIContractEncoder() enc = ABIContractEncoder()
enc.method('getDistributionFromRedistribution') enc.method('getDistributionFromRedistribution')
enc.typ(ABIContractType.BYTES32) v = strip_0x(redistribution)
enc.bytes32(redistribution) enc.typ_literal('(uint32,uint72,uint104)')
enc.bytes32(v[:64])
enc.bytes32(v[64:128])
enc.bytes32(v[128:192])
data = add_0x(enc.get()) data = add_0x(enc.get())
tx = self.template(sender_address, contract_address) tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data) tx = self.set_code(tx, data)

View File

@ -1,3 +1,3 @@
chainlib-eth~=0.4.6 chainlib-eth~=0.4.11
eth-erc20~=0.5.1 eth-erc20~=0.5.1
funga-eth~=0.6.0 funga-eth~=0.6.0

View File

@ -177,6 +177,7 @@ class TestRedistribution(TestDemurrageUnit):
o = c.redistributions(self.address, 0, sender_address=self.accounts[0]) o = c.redistributions(self.address, 0, sender_address=self.accounts[0])
redistribution = self.rpc.do(o) redistribution = self.rpc.do(o)
logg.debug('redistribution {}'.format(redistribution))
o = c.to_redistribution_supply(self.address, redistribution, sender_address=self.accounts[0]) o = c.to_redistribution_supply(self.address, redistribution, sender_address=self.accounts[0])
r = self.rpc.do(o) r = self.rpc.do(o)
supply = c.parse_to_redistribution_item(r) supply = c.parse_to_redistribution_item(r)

View File

@ -1,17 +1,24 @@
pragma solidity >= 0.8.0; pragma solidity >= 0.8.0;
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
contract DemurrageTokenSingleCap { contract DemurrageTokenSingleCap {
struct redistributionItem {
uint32 period;
uint72 value;
uint104 demurrage;
}
redistributionItem[] public redistributions; // uint51(unused) | uint64(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
// 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; // uint51(unused) | uint64(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 = 104; // uint8 constant shiftRedistributionDemurrage = 104;
uint256 constant maskRedistributionDemurrage = 0x0000000000ffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 36) - 1) << 140 // uint256 constant maskRedistributionDemurrage = 0x0000000000ffffffffffffffffffffffffffff00000000000000000000000000; // ((1 << 36) - 1) << 140
// Account balances // Account balances
mapping (address => uint256) account; mapping (address => uint256) account;
@ -105,6 +112,8 @@ contract DemurrageTokenSingleCap {
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, uint128 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress) public { constructor(string memory _name, string memory _symbol, uint8 _decimals, uint128 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress) public {
redistributionItem memory initialRedistribution;
// ACL setup // ACL setup
owner = msg.sender; owner = msg.sender;
minter[owner] = true; minter[owner] = true;
@ -120,7 +129,7 @@ contract DemurrageTokenSingleCap {
periodDuration = _periodMinutes * 60; periodDuration = _periodMinutes * 60;
demurrageAmount = uint128(nanoDivider) * 100; demurrageAmount = uint128(nanoDivider) * 100;
taxLevel = _taxLevelMinute; // Represents 38 decimal places taxLevel = _taxLevelMinute; // Represents 38 decimal places
bytes32 initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1); initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
redistributions.push(initialRedistribution); redistributions.push(initialRedistribution);
// Misc settings // Misc settings
@ -221,46 +230,82 @@ contract DemurrageTokenSingleCap {
// 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) public 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((_value << shiftRedistributionValue) & maskRedistributionValue);
// redistribution |= bytes32(_period & maskRedistributionPeriod);
// return redistribution;
// }
redistribution |= bytes32((_demurrageModifierPpm << shiftRedistributionDemurrage) & maskRedistributionDemurrage); function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) public pure returns(redistributionItem memory) {
redistribution |= bytes32((_value << shiftRedistributionValue) & maskRedistributionValue); redistributionItem memory redistribution;
redistribution |= bytes32(_period & maskRedistributionPeriod);
redistribution.period = uint32(_period);
redistribution.value = uint72(_value);
redistribution.demurrage = uint104(_demurrageModifierPpm);
return redistribution; return redistribution;
}
//
// // Serializes the demurrage period part of the redistribution word
// function toRedistributionPeriod(bytes32 redistribution) public pure returns (uint256) {
// return uint256(redistribution) & maskRedistributionPeriod;
// }
//
function toRedistributionPeriod(redistributionItem memory _redistribution) public pure returns (uint256) {
return uint256(_redistribution.period);
} }
// Serializes the demurrage period part of the redistribution word // // Serializes the supply part of the redistribution word
function toRedistributionPeriod(bytes32 redistribution) public pure returns (uint256) { // function toRedistributionSupply(bytes32 redistribution) public pure returns (uint256) {
return uint256(redistribution) & maskRedistributionPeriod; // return (uint256(redistribution) & kkRedistributionValue) >> shiftRedistributionValue;
// }
function toRedistributionSupply(redistributionItem memory _redistribution) public pure returns (uint256) {
return uint256(_redistribution.value);
} }
// Serializes the supply part of the redistribution word //
function toRedistributionSupply(bytes32 redistribution) public pure returns (uint256) { // // Serializes the number of participants part of the redistribution word
return (uint256(redistribution) & maskRedistributionValue) >> shiftRedistributionValue; // function toRedistributionDemurrageModifier(bytes32 redistribution) public pure returns (uint256) {
// return (uint256(redistribution) & maskRedistributionDemurrage) >> shiftRedistributionDemurrage;
// }
function toRedistributionDemurrageModifier(redistributionItem memory _redistribution) public pure returns (uint256) {
return uint256(_redistribution.demurrage);
} }
// Serializes the number of participants part of the redistribution word
function toRedistributionDemurrageModifier(bytes32 redistribution) public pure returns (uint256) {
return (uint256(redistribution) & maskRedistributionDemurrage) >> shiftRedistributionDemurrage;
}
// Client accessor to the redistributions array length // Client accessor to the redistributions array length
function redistributionCount() public view returns (uint256) { function redistributionCount() public view returns (uint256) {
return redistributions.length; return redistributions.length;
} }
//
// 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) {
// uint256 currentRedistribution;
// uint256 grownSupply;
//
// grownSupply = totalSupply();
// currentRedistribution = uint256(redistributions[redistributions.length-1]);
// currentRedistribution &= (~maskRedistributionValue);
// currentRedistribution |= (grownSupply << shiftRedistributionValue);
//
// redistributions[redistributions.length-1] = bytes32(currentRedistribution);
// return true;
// }
function saveRedistributionSupply() private returns (bool) { function saveRedistributionSupply() private returns (bool) {
uint256 currentRedistribution; redistributionItem memory currentRedistribution;
uint256 grownSupply; uint256 grownSupply;
grownSupply = totalSupply(); grownSupply = totalSupply();
currentRedistribution = uint256(redistributions[redistributions.length-1]); currentRedistribution = redistributions[redistributions.length-1];
currentRedistribution &= (~maskRedistributionValue); currentRedistribution.value = uint72(grownSupply);
currentRedistribution |= (grownSupply << shiftRedistributionValue);
redistributions[redistributions.length-1] = bytes32(currentRedistribution); redistributions[redistributions.length-1] = currentRedistribution;
return true; return true;
} }
@ -270,14 +315,15 @@ contract DemurrageTokenSingleCap {
} }
// Retrieve next redistribution if the period threshold has been crossed // Retrieve next redistribution if the period threshold has been crossed
function checkPeriod() private view returns (bytes32) { function checkPeriod() private view returns (redistributionItem memory) {
bytes32 lastRedistribution; redistributionItem memory lastRedistribution;
redistributionItem memory emptyRedistribution;
uint256 currentPeriod; uint256 currentPeriod;
lastRedistribution = redistributions[lastPeriod]; lastRedistribution = redistributions[lastPeriod];
currentPeriod = this.actualPeriod(); currentPeriod = this.actualPeriod();
if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) { if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
return bytes32(0x00); return emptyRedistribution;
} }
return lastRedistribution; return lastRedistribution;
} }
@ -289,7 +335,7 @@ contract DemurrageTokenSingleCap {
return difference / resolutionFactor; return difference / resolutionFactor;
} }
function getDistributionFromRedistribution(bytes32 _redistribution) public returns (uint256) { function getDistributionFromRedistribution(redistributionItem memory _redistribution) public returns (uint256) {
uint256 redistributionSupply; uint256 redistributionSupply;
uint256 redistributionDemurrage; uint256 redistributionDemurrage;
@ -299,7 +345,7 @@ contract DemurrageTokenSingleCap {
} }
// 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(redistributionItem memory _redistribution) private returns (uint256) {
uint256 unit; uint256 unit;
uint256 baseUnit; uint256 baseUnit;
@ -354,21 +400,34 @@ contract DemurrageTokenSingleCap {
return (block.timestamp - _target) / 60; return (block.timestamp - _target) / 60;
} }
function isEmptyRedistribution(redistributionItem memory _redistribution) public pure returns(bool) {
if (_redistribution.period > 0) {
return false;
}
if (_redistribution.value > 0) {
return false;
}
if (_redistribution.demurrage > 0) {
return false;
}
return true;
}
// Recalculate the demurrage modifier for the new period // 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. // 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) { function changePeriod() public returns (bool) {
bytes32 currentRedistribution; redistributionItem memory currentRedistribution;
bytes32 nextRedistribution; redistributionItem memory nextRedistribution;
redistributionItem memory lastRedistribution;
uint256 currentPeriod; uint256 currentPeriod;
uint256 lastDemurrageAmount; uint256 lastDemurrageAmount;
bytes32 lastRedistribution;
uint256 nextRedistributionDemurrage; uint256 nextRedistributionDemurrage;
uint256 demurrageCounts; uint256 demurrageCounts;
uint256 nextPeriod; uint256 nextPeriod;
applyDemurrage(); applyDemurrage();
currentRedistribution = checkPeriod(); currentRedistribution = checkPeriod();
if (currentRedistribution == bytes32(0x00)) { if (isEmptyRedistribution(currentRedistribution)) {
return false; return false;
} }
@ -389,18 +448,18 @@ contract DemurrageTokenSingleCap {
} }
// Reverse a value reduced by demurrage by the given period to its original value // Reverse a value reduced by demurrage by the given period to its original value
function growBy(uint256 _value, uint256 _period) public view returns (uint256) { // function growBy(uint256 _value, uint256 _period) public view returns (uint256) {
uint256 valueFactor; // uint256 valueFactor;
uint256 truncatedTaxLevel; // uint256 truncatedTaxLevel;
//
valueFactor = growthResolutionFactor; // valueFactor = growthResolutionFactor;
truncatedTaxLevel = taxLevel / nanoDivider; // truncatedTaxLevel = taxLevel / nanoDivider;
//
for (uint256 i = 0; i < _period; i++) { // for (uint256 i = 0; i < _period; i++) {
valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor); // valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
} // }
return (valueFactor * _value) / growthResolutionFactor; // return (valueFactor * _value) / growthResolutionFactor;
} // }
// Calculate a value reduced by demurrage by the given period // Calculate a value reduced by demurrage by the given period
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) { function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {