Add expiry implementation, after expire sink gets all

This commit is contained in:
lash 2023-02-10 12:22:50 +00:00
parent c25e018cd1
commit 23de062ab9
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
5 changed files with 95 additions and 8 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

@ -25,6 +25,8 @@ from dexif import from_fixed
# local imports
from erc20_demurrage_token.data import data_dir
from erc20_demurrage_token.seal import SealedContract
from erc20_demurrage_token.expiry import ExpiryContract
logg = logging.getLogger(__name__)
@ -71,7 +73,7 @@ class DemurrageTokenSettings:
)
class DemurrageToken(ERC20):
class DemurrageToken(ERC20, SealedContract, ExpiryContract):
__abi = {}
__bytecode = {}
@ -459,6 +461,8 @@ class DemurrageToken(ERC20):
return tx
def tax_level(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('taxLevel', contract_address, sender_address=sender_address)

View File

@ -92,7 +92,7 @@ class TestDemurrage(EthTesterCase):
period = getattr(self, 'period')
except AttributeError as e:
pass
self.deployer = TestTokenDeploy(self.rpc, period=period)
self.deployer = TestTokenDeploy(self.rpc, period=period, sink_address=self.accounts[9])
self.default_supply = self.deployer.default_supply
self.default_supply_cap = self.deployer.default_supply_cap
self.start_block = None

View File

@ -80,6 +80,10 @@ contract DemurrageTokenSingleCap {
// Address to send unallocated redistribution tokens
address public sinkAddress;
// timestamp when token contract expires
uint256 public expires;
bool expired;
// Implements ERC20
event Transfer(address indexed _from, address indexed _to, uint256 _value);
@ -108,6 +112,19 @@ contract DemurrageTokenSingleCap {
// EIP173
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
event SealStateChange(uint256 _sealState);
event Expired(uint256 _timestamp);
// property sealing
uint256 public sealState;
uint8 constant MINTER_STATE = 1;
uint8 constant SINK_STATE = 2;
uint8 constant EXPIRY_STATE = 4;
uint8 constant CAP_STATE = 8;
uint256 constant public maxSealState = 15;
constructor(string memory _name, string memory _symbol, uint8 _decimals, int128 _taxLevel, uint256 _periodMinutes, address _defaultSinkAddress) {
require(_taxLevel < (1 << 64));
redistributionItem memory initialRedistribution;
@ -137,15 +154,69 @@ contract DemurrageTokenSingleCap {
sinkAddress = _defaultSinkAddress;
}
function seal(uint256 _state) public returns(uint256) {
require(_state < 8, 'ERR_INVALID_STATE');
require(_state & sealState == 0, 'ERR_ALREADY_LOCKED');
sealState |= _state;
emit SealStateChange(sealState);
return uint256(sealState);
}
function isSealed(uint256 _state) public returns(bool) {
require(_state < maxSealState);
if (_state == 0) {
return sealState == maxSealState;
}
return _state & sealState == _state;
}
function setExpires(uint256 _expires) public {
require(!isSealed(EXPIRY_STATE));
require(!expired);
require(msg.sender == owner);
expires = _expires;
}
// Change sink address for redistribution
function setSinkAddress(address _sinkAddress) public {
require(!isSealed(SINK_STATE));
require(msg.sender == owner);
sinkAddress = _sinkAddress;
}
function applyExpiry() public returns(bool) {
if (expired) {
return true;
}
if (expires == 0) {
return false;
}
if (block.timestamp >= expires) {
account[sinkAddress] = totalSupply();
expired = true;
emit Expired(block.timestamp);
}
return expired;
}
function isExpiredAccount(address _account) public view returns(uint8) {
uint8 expiry_state;
if (expired) {
expiry_state = 1;
} else if (expires > 0 && block.timestamp >= expires) {
expiry_state = 1;
}
if (expiry_state > 0 && _account == sinkAddress) {
expiry_state = 2;
}
return expiry_state;
}
// Given address will be allowed to call the mintTo() function
function addMinter(address _minter) public returns (bool) {
require(!isSealed(MINTER_STATE));
require(msg.sender == owner);
minter[_minter] = true;
return true;
@ -153,6 +224,7 @@ contract DemurrageTokenSingleCap {
// Given address will no longer be allowed to call the mintTo() function
function removeMinter(address _minter) public returns (bool) {
require(!isSealed(MINTER_STATE));
require(msg.sender == owner || _minter == msg.sender);
minter[_minter] = false;
return true;
@ -163,6 +235,14 @@ contract DemurrageTokenSingleCap {
int128 baseBalance;
int128 currentDemurragedAmount;
uint256 periodCount;
uint8 expiryState;
expiryState = isExpiredAccount(_account);
if (expiryState == 1) {
return 0;
} else if (expiryState == 2) {
return totalSupply();
}
baseBalance = ABDKMath64x64.fromUInt(baseBalanceOf(_account));
@ -369,19 +449,22 @@ contract DemurrageTokenSingleCap {
}
// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
function applyDemurrage() public returns (uint256) {
function applyDemurrage() public returns (bool) {
return applyDemurrageLimited(0);
}
function applyDemurrageLimited(uint256 _rounds) public returns (uint256) {
// returns true if expired
function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
int128 v;
uint256 periodCount;
int128 periodPoint;
int128 lastDemurrageAmount;
require(!applyExpiry());
periodCount = getMinutesDelta(demurrageTimestamp);
if (periodCount == 0) {
return 0;
return false;
}
lastDemurrageAmount = demurrageAmount;
@ -398,7 +481,7 @@ contract DemurrageTokenSingleCap {
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
return periodCount;
return false;
}
// Return timestamp of start of period threshold