mirror of
git://holbrook.no/erc20-demurrage-token
synced 2024-11-25 01:16:45 +01:00
Add expiry implementation, after expire sink gets all
This commit is contained in:
parent
c25e018cd1
commit
23de062ab9
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user