erc20-demurrage-token

ERC20 token with redistributed continual demurrage
Info | Log | Files | Refs | README

DemurrageTokenSingleNocap.sol (23167B)


      1 pragma solidity >= 0.8.0;
      2 
      3 import "aux/ABDKMath64x64.sol";
      4 
      5 // SPDX-License-Identifier: AGPL-3.0-or-later
      6 
      7 contract DemurrageTokenSingleNocap {
      8 
      9 	uint256 constant VALUE_LIMIT = 1 << 63;
     10 
     11 	struct redistributionItem {
     12 		uint32 period;
     13 		uint72 value;
     14 		uint64 demurrage;
     15 	}
     16 	redistributionItem[] public redistributions;
     17 
     18 	// Account balances
     19 	mapping (address => uint256) account;
     20 	
     21 	// Cached demurrage amount, ppm with 38 digit resolution
     22 	//uint128 public demurrageAmount;
     23 	int128 public demurrageAmount;
     24 
     25 	// Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
     26 	uint256 public demurrageTimestamp;
     27 
     28 	// Implements EIP173
     29 	address public owner;
     30 
     31 	address newOwner;
     32 
     33 	// Implements ERC20
     34 	string public name;
     35 
     36 	// Implements ERC20
     37 	string public symbol;
     38 
     39 	// Implements ERC20
     40 	uint256 public immutable decimals;
     41 
     42 	uint256 supply;
     43 
     44 	// Last executed period
     45 	uint256 public lastPeriod;
     46 
     47 	// Last sink redistribution amount
     48 	uint256 public totalSink;
     49 
     50 	// Value of burnt tokens (burnt tokens do not decay)
     51 	uint256 burned;
     52 
     53 	// 128 bit resolution of the demurrage divisor
     54 	// (this constant x 1000000 is contained within 128 bits)
     55 	//uint256 constant nanoDivider = 100000000000000000000000000; // now nanodivider, 6 zeros less
     56 
     57 	// remaining decimal positions of nanoDivider to reach 38, equals precision in growth and decay
     58 	//uint256 constant growthResolutionFactor = 1000000000000;
     59 
     60 	// demurrage decimal width; 38 places
     61 	//uint256 public immutable resolutionFactor = nanoDivider * growthResolutionFactor; 
     62 
     63 	// Timestamp of start of periods (time which contract constructor was called)
     64 	uint256 public immutable periodStart;
     65 
     66 	// Duration of a single redistribution period in seconds
     67 	uint256 public immutable periodDuration;
     68 
     69 	// Demurrage in ppm per minute
     70 	//uint256 public immutable decayLevel;
     71 	// 64x64
     72 	int128 public immutable decayLevel;
     73 		
     74 	// Addresses allowed to mint new tokens
     75 	mapping (address => bool) minter;
     76 
     77 	// Storage for ERC20 approve/transferFrom methods
     78 	mapping (address => mapping (address => uint256 ) ) public allowance; // holder -> spender -> amount (amount is subject to demurrage)
     79 
     80 	// Address to send unallocated redistribution tokens
     81 	address public sinkAddress; 
     82 
     83 	// timestamp when token contract expires
     84 	uint256 public expires;
     85 	bool expired;
     86 
     87 	// supply xap
     88 	uint256 public maxSupply;
     89 
     90 	// Implements ERC20
     91 	event Transfer(address indexed _from, address indexed _to, uint256 _value);
     92 
     93 	// Implements ERC20
     94 	event Approval(address indexed _owner, address indexed _spender, uint256 _value);
     95 
     96 	// Implements Minter
     97 	event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value);
     98 
     99 	// New demurrage cache milestone calculated
    100 	event Decayed(uint256 indexed _period, uint256 indexed _periodCount, int128 indexed _oldAmount, int128 _newAmount);
    101 
    102 	// When a new period threshold has been crossed
    103 	event Period(uint256 _period);
    104 
    105 	// Redistribution applied on a single eligible account
    106 	event Redistribution(address indexed _account, uint256 indexed _period, uint256 _value);
    107 
    108 	// Temporary event used in development, will be removed on prod
    109 	//event Debug(bytes32 _foo);
    110 	event Debug(int128 indexed _foo, uint256 indexed _bar);
    111 
    112 	// Implements Burn
    113 	event Burn(address indexed _burner, uint256 _value);
    114 
    115 	// EIP173
    116 	event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
    117 
    118 	// Implements Expire
    119 	event Expired(uint256 _timestamp);
    120 
    121 	// Implements Expire
    122 	event ExpiryChange(uint256 indexed _oldTimestamp, uint256 _newTimestamp);
    123 
    124 	event Cap(uint256 indexed _oldCap, uint256 _newCap);
    125 
    126 	// Implements Seal
    127 	uint256 public sealState;
    128 	uint8 constant WRITER_STATE = 1;
    129 	uint8 constant SINK_STATE = 2;
    130 	uint8 constant EXPIRY_STATE = 4;
    131 	uint8 constant CAP_STATE = 8;
    132 	// Implements Seal
    133 	uint256 constant public maxSealState = 15;
    134 
    135 	// Implements Seal
    136 	event SealStateChange(bool indexed _final, uint256 _sealState);
    137 
    138 
    139 	constructor(string memory _name, string memory _symbol, uint8 _decimals, int128 _decayLevel, uint256 _periodMinutes, address _defaultSinkAddress) {
    140 		require(_decayLevel < (1 << 64));
    141 		redistributionItem memory initialRedistribution;
    142 
    143 		//require(ABDKMath64x64.toUInt(_decayLevel) == 0);
    144 
    145 		// ACL setup
    146 		owner = msg.sender;
    147 
    148 		// ERC20 setup
    149 		name = _name;
    150 		symbol = _symbol;
    151 		decimals = _decimals;
    152 
    153 		// Demurrage setup
    154 		demurrageTimestamp = block.timestamp;
    155 		periodStart = demurrageTimestamp;
    156 		periodDuration = _periodMinutes * 60;
    157 		demurrageAmount = ABDKMath64x64.fromUInt(1);
    158 
    159 		decayLevel = ABDKMath64x64.ln(_decayLevel);
    160 		initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
    161 		redistributions.push(initialRedistribution);
    162 
    163 		// Misc settings
    164 		sinkAddress = _defaultSinkAddress;
    165 	}
    166 
    167 	function seal(uint256 _state) public returns(uint256) {
    168 		require(msg.sender == owner);
    169 		require(_state < 16, 'ERR_INVALID_STATE');
    170 		require(_state & sealState == 0, 'ERR_ALREADY_LOCKED');
    171 		sealState |= _state;
    172 		emit SealStateChange(sealState == maxSealState, sealState);
    173 		return uint256(sealState);
    174 	}
    175 
    176 	function isSealed(uint256 _state) public view returns(bool) {
    177 		require(_state < maxSealState);
    178 		if (_state == 0) {
    179 			return sealState == maxSealState;
    180 		}
    181 		return _state & sealState == _state;
    182 	}
    183 
    184 	// Set when token expires. 
    185 	// Value is set it terms of redistribution periods.
    186 	// Cannot be set to a time in the past.
    187 	function setExpirePeriod(uint256 _expirePeriod) public {
    188 		uint256 r;
    189 		uint256 oldTimestamp;
    190 
    191 		require(!isSealed(EXPIRY_STATE));
    192 		require(!expired);
    193 		require(msg.sender == owner);
    194 		r = periodStart + (_expirePeriod * periodDuration);
    195 		require(r > expires);
    196 		oldTimestamp = expires;
    197 		expires = r;
    198 		emit ExpiryChange(oldTimestamp, expires);
    199 	}
    200 
    201 	// Change max token supply.
    202 	// Can only increase supply cap, not decrease.
    203 	function setMaxSupply(uint256 _cap) public {
    204 		require(!isSealed(CAP_STATE));
    205 		require(msg.sender == owner);
    206 		require(_cap > totalSupply());
    207 		emit Cap(maxSupply, _cap);
    208 		maxSupply = _cap;
    209 	}
    210 
    211 	// Change sink address for redistribution
    212 	function setSinkAddress(address _sinkAddress) public {
    213 		require(!isSealed(SINK_STATE));
    214 		require(msg.sender == owner);
    215 		sinkAddress = _sinkAddress;
    216 	}
    217 
    218 	// Expire the contract if expire is set and we have gone over the threshold.
    219 	// Finalizes demurrage up to the timestamp of the expiry. 
    220 	// The first approve, transfer or transferFrom call that hits the ex == 2 will get the tx mined. but without the actual effect. Otherwise we would have to wait until an external egent called applyExpiry to get the correct final balance.
    221 	// Implements Expire
    222 	function applyExpiry() public returns(uint8) {
    223 		if (expired) {
    224 			return 1;
    225 		}
    226 		if (expires == 0) {
    227 			return 0;
    228 		}
    229 		if (block.timestamp >= expires) {
    230 			applyDemurrageLimited(expires - demurrageTimestamp / 60);
    231 			expired = true;
    232 			emit Expired(block.timestamp);
    233 			changePeriod();
    234 			return 2;
    235 		}
    236 		return 0;
    237 	}
    238 
    239 	// Given address will be allowed to call the mintTo() function
    240 	// Implements Writer
    241 	function addWriter(address _minter) public returns (bool) {
    242 		require(!isSealed(WRITER_STATE));
    243 		require(msg.sender == owner);
    244 		minter[_minter] = true;
    245 		return true;
    246 	}
    247 
    248 	// Given address will no longer be allowed to call the mintTo() function
    249 	// Implements Writer
    250 	function deleteWriter(address _minter) public returns (bool) {
    251 		require(!isSealed(WRITER_STATE));
    252 		require(msg.sender == owner || _minter == msg.sender);
    253 		minter[_minter] = false;
    254 		return true;
    255 	}
    256 
    257 	// Implements Writer
    258 	function isWriter(address _minter) public view returns(bool) {
    259 		return minter[_minter] || _minter == owner;
    260 	}
    261 
    262 	/// Implements ERC20
    263 	function balanceOf(address _account) public view returns (uint256) {
    264 		int128 baseBalance;
    265 		int128 currentDemurragedAmount;
    266 		uint256 periodCount;
    267 
    268 		baseBalance = ABDKMath64x64.fromUInt(baseBalanceOf(_account));
    269 
    270 		periodCount = getMinutesDelta(demurrageTimestamp);
    271 
    272 		currentDemurragedAmount = ABDKMath64x64.mul(baseBalance, demurrageAmount);
    273 		return decayBy(ABDKMath64x64.toUInt(currentDemurragedAmount), periodCount);
    274 	}
    275 
    276 	// Balance unmodified by demurrage
    277 	function baseBalanceOf(address _account) public view returns (uint256) {
    278 		return account[_account];
    279 	}
    280 
    281 	/// Increases base balance for a single account
    282 	function increaseBaseBalance(address _account, uint256 _delta) private returns (bool) {
    283 		uint256 oldBalance;
    284 		uint256 workAccount;
    285 
    286 		workAccount = uint256(account[_account]);
    287 	
    288 		if (_delta == 0) {
    289 			return false;
    290 		}
    291 
    292 		oldBalance = baseBalanceOf(_account);
    293 		account[_account] = oldBalance + _delta;
    294 		return true;
    295 	}
    296 
    297 	/// Decreases base balance for a single account
    298 	function decreaseBaseBalance(address _account, uint256 _delta) private returns (bool) {
    299 		uint256 oldBalance;
    300 		uint256 workAccount;
    301 
    302 		workAccount = uint256(account[_account]);
    303 
    304 		if (_delta == 0) {
    305 			return false;
    306 		}
    307 
    308 		oldBalance = baseBalanceOf(_account);	
    309 		require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard
    310 		account[_account] = oldBalance - _delta;
    311 		return true;
    312 	}
    313 
    314 	// Send full balance of one account to another
    315 	function sweep(address _account) public returns (uint256) {
    316 		uint256 v;
    317 
    318 		v = account[msg.sender];
    319 		account[msg.sender] = 0;
    320 		account[_account] += v;
    321 		emit Transfer(msg.sender, _account, v);
    322 		return v;
    323 	}
    324 
    325 	// Creates new tokens out of thin air, and allocates them to the given address
    326 	// Triggers tax
    327 	// Implements Minter
    328 	function mintTo(address _beneficiary, uint256 _amount) public returns (bool) {
    329 		uint256 baseAmount;
    330 
    331 		require(applyExpiry() == 0);
    332 		require(minter[msg.sender] || msg.sender == owner, 'ERR_ACCESS');
    333 
    334 		changePeriod();
    335 		if (maxSupply > 0) {
    336 			require(supply + _amount <= maxSupply);
    337 		}
    338 		supply += _amount;
    339 
    340 		baseAmount = toBaseAmount(_amount);
    341 		increaseBaseBalance(_beneficiary, baseAmount);
    342 		emit Mint(msg.sender, _beneficiary, _amount);
    343 		saveRedistributionSupply();
    344 		return true;
    345 	}
    346 
    347 	// Implements Minter
    348 	function mint(address _beneficiary, uint256 _amount, bytes calldata _data) public {
    349 		_data;
    350 		mintTo(_beneficiary, _amount);
    351 	}
    352 
    353 	// Implements Minter
    354 	function safeMint(address _beneficiary, uint256 _amount, bytes calldata _data) public {
    355 		_data;
    356 		mintTo(_beneficiary, _amount);
    357 	}
    358 
    359 	// Deserializes the redistribution word
    360 	function toRedistribution(uint256 _participants, int128 _demurrageModifier, uint256 _value, uint256 _period) public pure returns(redistributionItem memory) {
    361 		redistributionItem memory redistribution;
    362 
    363 		redistribution.period = uint32(_period);
    364 		redistribution.value = uint72(_value);
    365 		redistribution.demurrage = uint64(uint128(_demurrageModifier) & 0xffffffffffffffff);
    366 		_participants;
    367 		return redistribution;
    368 
    369 	}
    370 
    371 	// Serializes the demurrage period part of the redistribution word
    372 	function toRedistributionPeriod(redistributionItem memory _redistribution) public pure returns (uint256) {
    373 		return uint256(_redistribution.period);
    374 	}
    375 
    376 	// Serializes the supply part of the redistribution word
    377 	function toRedistributionSupply(redistributionItem memory _redistribution) public pure returns (uint256) {
    378 		return uint256(_redistribution.value);
    379 	}
    380 
    381 	// Serializes the number of participants part of the redistribution word
    382 	function toRedistributionDemurrageModifier(redistributionItem memory _redistribution) public pure returns (int128) {
    383 		int128 r;
    384 
    385 		r = int128(int64(_redistribution.demurrage) & int128(0x0000000000000000ffffffffffffffff));
    386 		if (r == 0) {
    387 			r = ABDKMath64x64.fromUInt(1);
    388 		}
    389 		return r;
    390 	}
    391 
    392 	// Client accessor to the redistributions array length
    393 	function redistributionCount() public view returns (uint256) {
    394 		return redistributions.length;
    395 	}
    396 
    397 	// Save the current total supply amount to the current redistribution period
    398 	function saveRedistributionSupply() private returns (bool) {
    399 		redistributionItem memory currentRedistribution;
    400 		uint256 grownSupply;
    401 
    402 		grownSupply = totalSupply();
    403 		currentRedistribution = redistributions[redistributions.length-1];
    404 		currentRedistribution.value = uint72(grownSupply);
    405 
    406 		redistributions[redistributions.length-1] = currentRedistribution;
    407 		return true;
    408 	}
    409 
    410 	// Get the demurrage period of the current block number
    411 	function actualPeriod() public view returns (uint128) {
    412 		return uint128((block.timestamp - periodStart) / periodDuration + 1);
    413 	}
    414 
    415 	// Retrieve next redistribution if the period threshold has been crossed
    416 	function checkPeriod() private view returns (redistributionItem memory) {
    417 		redistributionItem memory lastRedistribution;
    418 		redistributionItem memory emptyRedistribution;
    419 		uint256 currentPeriod;
    420 
    421 		lastRedistribution =  redistributions[lastPeriod];
    422 		currentPeriod = this.actualPeriod();
    423 		if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
    424 			return emptyRedistribution;
    425 		}
    426 		return lastRedistribution;
    427 	}
    428 
    429 	function getDistribution(uint256 _supply, int128 _demurrageAmount) public pure returns (uint256) {
    430 		int128 difference;
    431 
    432 		difference = ABDKMath64x64.mul(ABDKMath64x64.fromUInt(_supply), ABDKMath64x64.sub(ABDKMath64x64.fromUInt(1), _demurrageAmount));
    433 		return _supply - ABDKMath64x64.toUInt(difference);
    434 			
    435 	}
    436 
    437 	function getDistributionFromRedistribution(redistributionItem memory _redistribution) public pure returns (uint256) {
    438 		uint256 redistributionSupply;
    439 		int128 redistributionDemurrage;
    440 
    441 		redistributionSupply = toRedistributionSupply(_redistribution);
    442 		redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
    443 		return getDistribution(redistributionSupply, redistributionDemurrage);
    444 	}
    445 
    446 	// Returns the amount sent to the sink address
    447 	function applyDefaultRedistribution(redistributionItem memory _redistribution) private returns (uint256) {
    448 		uint256 unit;
    449 		uint256 baseUnit;
    450 	
    451 		unit = totalSupply() - getDistributionFromRedistribution(_redistribution);	
    452 		baseUnit = toBaseAmount(unit) - totalSink;
    453 		increaseBaseBalance(sinkAddress, baseUnit);
    454 		emit Redistribution(sinkAddress, _redistribution.period, unit);
    455 		lastPeriod += 1;
    456 		totalSink += baseUnit;
    457 		return unit;
    458 	}
    459 
    460 	// Recalculate the demurrage modifier for the new period
    461 	// 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.
    462 	function changePeriod() public returns (bool) {
    463 		redistributionItem memory currentRedistribution;
    464 		redistributionItem memory nextRedistribution;
    465 		redistributionItem memory lastRedistribution;
    466 		uint256 currentPeriod;
    467 		int128 lastDemurrageAmount;
    468 		int128 nextRedistributionDemurrage;
    469 		uint256 demurrageCounts;
    470 		uint256 nextPeriod;
    471 
    472 		applyDemurrage();
    473 		currentRedistribution = checkPeriod();
    474 		if (isEmptyRedistribution(currentRedistribution)) {
    475 			return false;
    476 		}
    477 
    478 		// calculate the decay from previous redistributino
    479 		lastRedistribution = redistributions[lastPeriod];
    480 		currentPeriod = toRedistributionPeriod(currentRedistribution);
    481 		nextPeriod = currentPeriod + 1;
    482 		lastDemurrageAmount = toRedistributionDemurrageModifier(lastRedistribution);
    483 		demurrageCounts = (periodDuration * currentPeriod) / 60;
    484 		// TODO refactor decayby to take int128 then DRY with it
    485 		nextRedistributionDemurrage = ABDKMath64x64.exp(ABDKMath64x64.mul(decayLevel, ABDKMath64x64.fromUInt(demurrageCounts)));
    486 		nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply(), nextPeriod);
    487 		redistributions.push(nextRedistribution);
    488 
    489 		applyDefaultRedistribution(nextRedistribution);
    490 		emit Period(nextPeriod);
    491 		return true;
    492 	}
    493 
    494 	// Calculate the time delta in whole minutes passed between given timestamp and current timestamp
    495 	function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) {
    496 		return (block.timestamp - _lastTimestamp) / 60;
    497 	}
    498 
    499 	// Calculate and cache the demurrage value corresponding to the (period of the) time of the method call
    500 	function applyDemurrage() public returns (uint256) {
    501 		return applyDemurrageLimited(0);
    502 	}
    503 
    504 	// returns true if expired
    505 	function applyDemurrageLimited(uint256 _rounds) public returns (uint256) {
    506 		int128 v;
    507 		uint256 periodCount;
    508 		int128 periodPoint;
    509 		int128 lastDemurrageAmount;
    510 
    511 		if (expired) {
    512 			return 0; 
    513 		}
    514 
    515 		periodCount = getMinutesDelta(demurrageTimestamp);
    516 		if (periodCount == 0) {
    517 			return 0;
    518 		}
    519 		lastDemurrageAmount = demurrageAmount;
    520 	
    521 		// safety limit for exponential calculation to ensure that we can always
    522 		// execute this code no matter how much time passes.			
    523 		if (_rounds > 0 && _rounds < periodCount) {
    524 			periodCount = _rounds;
    525 		}
    526 
    527 		periodPoint = ABDKMath64x64.fromUInt(periodCount);
    528 		v = ABDKMath64x64.mul(decayLevel, periodPoint);
    529 		v = ABDKMath64x64.exp(v);
    530 		demurrageAmount = ABDKMath64x64.mul(demurrageAmount, v);
    531 
    532 		demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
    533 		emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
    534 		return periodCount;
    535 	}
    536 
    537 	// Return timestamp of start of period threshold
    538 	function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) {
    539 		return periodStart + (_periodCount * periodDuration);
    540 	}
    541 
    542 	// Amount of demurrage cycles inbetween the current timestamp and the given target time
    543 	function demurrageCycles(uint256 _target) public view returns (uint256) {
    544 		return (block.timestamp - _target) / 60;
    545 	}
    546 
    547 	// Equality check for empty redistribution data
    548 	function isEmptyRedistribution(redistributionItem memory _redistribution) public pure returns(bool) {
    549 		if (_redistribution.period > 0) {
    550 			return false;
    551 		}
    552 		if (_redistribution.value > 0) {
    553 			return false;
    554 		}
    555 		if (_redistribution.demurrage > 0) {
    556 			return false;
    557 		}
    558 		return true;
    559 	}
    560 
    561 
    562 	// Calculate a value reduced by demurrage by the given period
    563 	function decayBy(uint256 _value, uint256 _period)  public view returns (uint256) {
    564 		int128 valuePoint;
    565 		int128 periodPoint;
    566 		int128 v;
    567 	
    568 		valuePoint = ABDKMath64x64.fromUInt(_value);
    569 		periodPoint = ABDKMath64x64.fromUInt(_period);
    570 
    571 		v = ABDKMath64x64.mul(decayLevel, periodPoint);
    572 		v = ABDKMath64x64.exp(v);
    573 		v = ABDKMath64x64.mul(valuePoint, v);
    574 		return ABDKMath64x64.toUInt(v);
    575 	}
    576 
    577 
    578 	// Inflates the given amount according to the current demurrage modifier
    579 	function toBaseAmount(uint256 _value) public view returns (uint256) {
    580 		int128 r;
    581 		r = ABDKMath64x64.div(ABDKMath64x64.fromUInt(_value), demurrageAmount);
    582 		return ABDKMath64x64.toUInt(r);
    583 	}
    584 
    585 	// Triggers tax and/or redistribution
    586 	// Implements ERC20
    587 	function approve(address _spender, uint256 _value) public returns (bool) {
    588 		uint256 baseValue;
    589 		uint8 ex;
    590 
    591 		ex = applyExpiry();
    592 		if (ex == 2) {
    593 			return false;	
    594 		} else if (ex > 0) {
    595 			revert('EXPIRED');
    596 		}
    597 		if (allowance[msg.sender][_spender] > 0) {
    598 			require(_value == 0, 'ZERO_FIRST');
    599 		}
    600 		
    601 		changePeriod();
    602 
    603 		// dex code will attempt uint256max approve, but basevalue calc is only valid up to a maximum of 2^63-1
    604 		// skip the base value calc for higher values
    605 		if (_value <= VALUE_LIMIT) {
    606 			baseValue = toBaseAmount(_value);
    607 		} else {
    608 			baseValue = VALUE_LIMIT;
    609 		}
    610 
    611 		allowance[msg.sender][_spender] = baseValue;
    612 		emit Approval(msg.sender, _spender, _value);
    613 		return true;
    614 	}
    615 
    616 	// Reduce allowance by amount
    617 	function decreaseAllowance(address _spender, uint256 _value) public returns (bool) {
    618 		uint256 baseValue;
    619 
    620 		baseValue = toBaseAmount(_value);
    621 		require(allowance[msg.sender][_spender] >= baseValue);
    622 		
    623 		changePeriod();
    624 
    625 		allowance[msg.sender][_spender] -= baseValue;
    626 		emit Approval(msg.sender, _spender, allowance[msg.sender][_spender]);
    627 		return true;
    628 	}
    629 
    630 	// Increase allowance by amount
    631 	function increaseAllowance(address _spender, uint256 _value) public returns (bool) {
    632 		uint256 baseValue;
    633 
    634 		changePeriod();
    635 
    636 		baseValue = toBaseAmount(_value);
    637 
    638 		allowance[msg.sender][_spender] += baseValue;
    639 		emit Approval(msg.sender, _spender, allowance[msg.sender][_spender]);
    640 		return true;
    641 	}
    642 
    643 	// Triggers tax and/or redistribution
    644 	// Implements ERC20
    645 	function transfer(address _to, uint256 _value) public returns (bool) {
    646 		uint256 baseValue;
    647 		bool result;
    648 		uint8 ex;
    649 
    650 		ex = applyExpiry();
    651 		if (ex == 2) {
    652 			return false;	
    653 		} else if (ex > 0) {
    654 			revert('EXPIRED');
    655 		}
    656 		changePeriod();
    657 
    658 		baseValue = toBaseAmount(_value);
    659 		result = transferBase(msg.sender, _to, baseValue);
    660 		emit Transfer(msg.sender, _to, _value);
    661 		return result;
    662 	}
    663 
    664 	// Triggers tax and/or redistribution
    665 	// Implements ERC20
    666 	function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
    667 		uint256 baseValue;
    668 		bool result;
    669 		uint8 ex;
    670 
    671 		ex = applyExpiry();
    672 		if (ex == 2) {
    673 			return false;	
    674 		} else if (ex > 0) {
    675 			revert('EXPIRED');
    676 		}
    677 		changePeriod();
    678 
    679 		baseValue = toBaseAmount(_value);
    680 		require(allowance[_from][msg.sender] >= baseValue);
    681 
    682 		allowance[_from][msg.sender] -= baseValue;
    683 		result = transferBase(_from, _to, baseValue);
    684 
    685 		emit Transfer(_from, _to, _value);
    686 		return result;
    687 	}
    688 
    689 	// ERC20 transfer backend for transfer, transferFrom
    690 	function transferBase(address _from, address _to, uint256 _value) private returns (bool) {
    691 		decreaseBaseBalance(_from, _value);
    692 		increaseBaseBalance(_to, _value);
    693 
    694 		return true;
    695 	}
    696 
    697 	// Implements EIP173
    698 	function transferOwnership(address _newOwner) public returns (bool) {
    699 		address oldOwner;
    700 
    701 		require(msg.sender == owner);
    702 		oldOwner = owner;
    703 		owner = _newOwner;
    704 
    705 		emit OwnershipTransferred(oldOwner, owner);
    706 		return true;
    707 	}
    708 
    709 	// Explicitly and irretrievably burn tokens
    710 	// Only token minters can burn tokens
    711 	// Implements Burner
    712 	function burn(uint256 _value) public returns(bool) {
    713 		require(applyExpiry() == 0);
    714 		require(minter[msg.sender] || msg.sender == owner, 'ERR_ACCESS');
    715 		require(_value <= account[msg.sender]);
    716 		uint256 _delta = toBaseAmount(_value);
    717 
    718 		//applyDemurrage();
    719 		decreaseBaseBalance(msg.sender, _delta);
    720 		burned += _value;
    721 		emit Burn(msg.sender, _value);
    722 		return true;
    723 	}
    724 
    725 	// Implements Burner
    726 	function burn(address _from, uint256 _value, bytes calldata _data) public {
    727 		require(_from == msg.sender, 'ERR_ONLY_SELF_BURN');
    728 		_data;
    729 		burn(_value);
    730 	}
    731 
    732 	// Implements Burner
    733 	function burn() public returns(bool) {
    734 		return burn(account[msg.sender]);
    735 	}
    736 
    737 	// Implements ERC20
    738 	function totalSupply() public view returns (uint256) {
    739 		return supply - burned;
    740 	}
    741 
    742 	// Return total number of burned tokens
    743 	// Implements Burner
    744 	function totalBurned() public view returns (uint256) {
    745 		return burned;
    746 	}
    747 
    748 	// Return total number of tokens ever minted
    749 	// Implements Burner
    750 	function totalMinted() public view returns (uint256) {
    751 		return supply;
    752 	}
    753 
    754 
    755 	// Implements EIP165
    756 	function supportsInterface(bytes4 _sum) public pure returns (bool) {
    757 		if (_sum == 0xb61bc941) { // ERC20
    758 			return true;
    759 		}
    760 		if (_sum == 0x5878bcf4) { // Minter
    761 			return true;
    762 		}
    763 		if (_sum == 0xbc4babdd) { // Burner
    764 			return true;
    765 		}
    766 		if (_sum == 0x0d7491f8) { // Seal
    767 			return true;
    768 		}
    769 		if (_sum == 0xabe1f1f5) { // Writer
    770 			return true;
    771 		}
    772 		if (_sum == 0x841a0e94) { // Expire
    773 			return true;
    774 		}
    775 		if (_sum == 0x01ffc9a7) { // ERC165
    776 			return true;
    777 		}
    778 		if (_sum == 0x9493f8b2) { // ERC173
    779 			return true;
    780 		}
    781 		if (_sum == 0xd0017968) { // ERC5678Ext20
    782 			return true;
    783 		}
    784 		return false;
    785 	}
    786 }