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 # local imports
from erc20_demurrage_token.data import data_dir 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__) logg = logging.getLogger(__name__)
@ -71,7 +73,7 @@ class DemurrageTokenSettings:
) )
class DemurrageToken(ERC20): class DemurrageToken(ERC20, SealedContract, ExpiryContract):
__abi = {} __abi = {}
__bytecode = {} __bytecode = {}
@ -459,6 +461,8 @@ class DemurrageToken(ERC20):
return tx return tx
def tax_level(self, contract_address, sender_address=ZERO_ADDRESS): def tax_level(self, contract_address, sender_address=ZERO_ADDRESS):
return self.call_noarg('taxLevel', contract_address, sender_address=sender_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') period = getattr(self, 'period')
except AttributeError as e: except AttributeError as e:
pass 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 = self.deployer.default_supply
self.default_supply_cap = self.deployer.default_supply_cap self.default_supply_cap = self.deployer.default_supply_cap
self.start_block = None self.start_block = None

View File

@ -80,6 +80,10 @@ contract DemurrageTokenSingleCap {
// Address to send unallocated redistribution tokens // Address to send unallocated redistribution tokens
address public sinkAddress; address public sinkAddress;
// timestamp when token contract expires
uint256 public expires;
bool expired;
// Implements ERC20 // Implements ERC20
event Transfer(address indexed _from, address indexed _to, uint256 _value); event Transfer(address indexed _from, address indexed _to, uint256 _value);
@ -108,6 +112,19 @@ contract DemurrageTokenSingleCap {
// EIP173 // EIP173
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // 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) { constructor(string memory _name, string memory _symbol, uint8 _decimals, int128 _taxLevel, uint256 _periodMinutes, address _defaultSinkAddress) {
require(_taxLevel < (1 << 64)); require(_taxLevel < (1 << 64));
redistributionItem memory initialRedistribution; redistributionItem memory initialRedistribution;
@ -137,15 +154,69 @@ contract DemurrageTokenSingleCap {
sinkAddress = _defaultSinkAddress; 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 // Change sink address for redistribution
function setSinkAddress(address _sinkAddress) public { function setSinkAddress(address _sinkAddress) public {
require(!isSealed(SINK_STATE));
require(msg.sender == owner); require(msg.sender == owner);
sinkAddress = _sinkAddress; 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 // Given address will be allowed to call the mintTo() function
function addMinter(address _minter) public returns (bool) { function addMinter(address _minter) public returns (bool) {
require(!isSealed(MINTER_STATE));
require(msg.sender == owner); require(msg.sender == owner);
minter[_minter] = true; minter[_minter] = true;
return true; return true;
@ -153,6 +224,7 @@ contract DemurrageTokenSingleCap {
// Given address will no longer be allowed to call the mintTo() function // Given address will no longer be allowed to call the mintTo() function
function removeMinter(address _minter) public returns (bool) { function removeMinter(address _minter) public returns (bool) {
require(!isSealed(MINTER_STATE));
require(msg.sender == owner || _minter == msg.sender); require(msg.sender == owner || _minter == msg.sender);
minter[_minter] = false; minter[_minter] = false;
return true; return true;
@ -163,6 +235,14 @@ contract DemurrageTokenSingleCap {
int128 baseBalance; int128 baseBalance;
int128 currentDemurragedAmount; int128 currentDemurragedAmount;
uint256 periodCount; uint256 periodCount;
uint8 expiryState;
expiryState = isExpiredAccount(_account);
if (expiryState == 1) {
return 0;
} else if (expiryState == 2) {
return totalSupply();
}
baseBalance = ABDKMath64x64.fromUInt(baseBalanceOf(_account)); 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 // 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); return applyDemurrageLimited(0);
} }
function applyDemurrageLimited(uint256 _rounds) public returns (uint256) { // returns true if expired
function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
int128 v; int128 v;
uint256 periodCount; uint256 periodCount;
int128 periodPoint; int128 periodPoint;
int128 lastDemurrageAmount; int128 lastDemurrageAmount;
require(!applyExpiry());
periodCount = getMinutesDelta(demurrageTimestamp); periodCount = getMinutesDelta(demurrageTimestamp);
if (periodCount == 0) { if (periodCount == 0) {
return 0; return false;
} }
lastDemurrageAmount = demurrageAmount; lastDemurrageAmount = demurrageAmount;
@ -398,7 +481,7 @@ contract DemurrageTokenSingleCap {
demurrageTimestamp = demurrageTimestamp + (periodCount * 60); demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount); emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
return periodCount; return false;
} }
// Return timestamp of start of period threshold // Return timestamp of start of period threshold