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 }