mirror of
git://holbrook.no/erc20-demurrage-token
synced 2026-01-11 13:47:58 +01:00
Compare commits
2 Commits
bcc957f861
...
ae2c1b4124
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae2c1b4124 | ||
|
|
ffc041c1a3 |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
from .base import *
|
from .newbase import *
|
||||||
|
|||||||
134
python/erc20_demurrage_token/unittest/newbase.py
Normal file
134
python/erc20_demurrage_token/unittest/newbase.py
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
# standard imports
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
# external imports
|
||||||
|
from chainlib.eth.unittest.ethtester import EthTesterCase
|
||||||
|
from chainlib.eth.tx import (
|
||||||
|
receipt,
|
||||||
|
)
|
||||||
|
from chainlib.eth.block import (
|
||||||
|
block_latest,
|
||||||
|
block_by_number,
|
||||||
|
)
|
||||||
|
from chainlib.eth.nonce import RPCNonceOracle
|
||||||
|
from chainlib.eth.constant import ZERO_ADDRESS
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from erc20_demurrage_token import (
|
||||||
|
DemurrageTokenSettings,
|
||||||
|
DemurrageToken,
|
||||||
|
)
|
||||||
|
|
||||||
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
#BLOCKTIME = 5 # seconds
|
||||||
|
TAX_LEVEL = int(10000 * 2) # 2%
|
||||||
|
# calc "1-(0.98)^(1/518400)" <- 518400 = 30 days of blocks
|
||||||
|
# 0.00000003897127107225
|
||||||
|
#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month
|
||||||
|
PERIOD = 10
|
||||||
|
|
||||||
|
|
||||||
|
class TestTokenDeploy:
|
||||||
|
|
||||||
|
"""tax level is ppm, 1000000 = 100%"""
|
||||||
|
def __init__(self, rpc, token_symbol='FOO', token_name='Foo Token', sink_address=ZERO_ADDRESS, supply=10**12, tax_level=TAX_LEVEL, period=PERIOD):
|
||||||
|
self.tax_level = tax_level
|
||||||
|
self.period_seconds = period * 60
|
||||||
|
|
||||||
|
self.settings = DemurrageTokenSettings()
|
||||||
|
self.settings.name = token_name
|
||||||
|
self.settings.symbol = token_symbol
|
||||||
|
self.settings.decimals = 6
|
||||||
|
self.settings.demurrage_level = tax_level ** (1 / period)
|
||||||
|
self.settings.period_minutes = period
|
||||||
|
self.settings.sink_address = sink_address
|
||||||
|
self.sink_address = self.settings.sink_address
|
||||||
|
logg.debug('using demurrage token settings: {}'.format(self.settings))
|
||||||
|
|
||||||
|
o = block_latest()
|
||||||
|
self.start_block = rpc.do(o)
|
||||||
|
|
||||||
|
o = block_by_number(self.start_block, include_tx=False)
|
||||||
|
r = rpc.do(o)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.start_time = int(r['timestamp'], 16)
|
||||||
|
except TypeError:
|
||||||
|
self.start_time = int(r['timestamp'])
|
||||||
|
|
||||||
|
self.default_supply = supply
|
||||||
|
#self.default_supply_cap = int(self.default_supply * 10)
|
||||||
|
self.default_supply_cap = 0
|
||||||
|
|
||||||
|
|
||||||
|
def deploy(self, rpc, deployer_address, interface, mode, supply_cap=0):
|
||||||
|
tx_hash = None
|
||||||
|
o = None
|
||||||
|
(tx_hash, o) = interface.constructor(deployer_address, self.settings, redistribute=False, cap=0)
|
||||||
|
|
||||||
|
r = rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = rpc.do(o)
|
||||||
|
assert r['status'] == 1
|
||||||
|
self.start_block = r['block_number']
|
||||||
|
self.address = r['contract_address']
|
||||||
|
|
||||||
|
o = block_by_number(r['block_number'])
|
||||||
|
r = rpc.do(o)
|
||||||
|
self.start_time = r['timestamp']
|
||||||
|
|
||||||
|
return self.address
|
||||||
|
|
||||||
|
|
||||||
|
class TestDemurrage(EthTesterCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestDemurrage, self).setUp()
|
||||||
|
period = PERIOD
|
||||||
|
try:
|
||||||
|
period = getattr(self, 'period')
|
||||||
|
except AttributeError as e:
|
||||||
|
pass
|
||||||
|
self.deployer = TestTokenDeploy(self.rpc, period=period)
|
||||||
|
self.default_supply = self.deployer.default_supply
|
||||||
|
self.default_supply_cap = self.deployer.default_supply_cap
|
||||||
|
self.start_block = None
|
||||||
|
self.address = None
|
||||||
|
self.start_time = None
|
||||||
|
|
||||||
|
|
||||||
|
def deploy(self, interface):
|
||||||
|
self.address = self.deployer.deploy(self.rpc, self.accounts[0], interface, mode, supply_cap=self.default_supply_cap)
|
||||||
|
self.start_block = self.deployer.start_block
|
||||||
|
self.start_time = self.deployer.start_time
|
||||||
|
self.tax_level = self.deployer.tax_level
|
||||||
|
self.period_seconds = self.deployer.period_seconds
|
||||||
|
self.sink_address = self.deployer.sink_address
|
||||||
|
|
||||||
|
logg.debug('contract address {} start block {} start time {}'.format(self.address, self.start_block, self.start_time))
|
||||||
|
|
||||||
|
|
||||||
|
def assert_within_lower(self, v, target, tolerance_ppm):
|
||||||
|
lower_target = target - (target * (tolerance_ppm / 1000000))
|
||||||
|
self.assertGreaterEqual(v, lower_target)
|
||||||
|
self.assertLessEqual(v, target)
|
||||||
|
logg.debug('asserted within lower {} <= {} <= {}'.format(lower_target, v, target))
|
||||||
|
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestDemurrageDefault(TestDemurrage):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestDemurrageDefault, self).setUp()
|
||||||
|
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
|
self.deploy(c)
|
||||||
|
|
||||||
|
logg.info('deployed with mode {}'.format(self.mode))
|
||||||
@ -1,3 +1,3 @@
|
|||||||
chainlib-eth>=0.1.0,<0.2.0
|
chainlib-eth~=0.4.11
|
||||||
eth-erc20~=0.3.0
|
eth-erc20~=0.5.0
|
||||||
funga-eth~=0.6.0
|
funga-eth~=0.6.0
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
pragma solidity >= 0.8.0;
|
pragma solidity >= 0.8.0;
|
||||||
|
|
||||||
|
|
||||||
|
import "aux/ABDKMath64x64.sol";
|
||||||
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
contract DemurrageTokenSingleCap {
|
contract DemurrageTokenSingleCap {
|
||||||
|
|
||||||
struct redistributionItem {
|
struct redistributionItem {
|
||||||
uint32 period;
|
uint32 period;
|
||||||
uint72 value;
|
uint72 value;
|
||||||
uint104 demurrage;
|
uint40 demurrage;
|
||||||
}
|
}
|
||||||
redistributionItem[] public redistributions; // uint51(unused) | uint64(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
|
redistributionItem[] public redistributions; // uint51(unused) | uint64(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period)
|
||||||
|
|
||||||
@ -15,7 +17,8 @@ contract DemurrageTokenSingleCap {
|
|||||||
mapping (address => uint256) account;
|
mapping (address => uint256) account;
|
||||||
|
|
||||||
// Cached demurrage amount, ppm with 38 digit resolution
|
// Cached demurrage amount, ppm with 38 digit resolution
|
||||||
uint128 public demurrageAmount;
|
//uint128 public demurrageAmount;
|
||||||
|
int128 public demurrageAmount;
|
||||||
|
|
||||||
// Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
|
// Cached demurrage timestamp; the timestamp for which demurrageAmount was last calculated
|
||||||
uint256 public demurrageTimestamp;
|
uint256 public demurrageTimestamp;
|
||||||
@ -49,13 +52,13 @@ contract DemurrageTokenSingleCap {
|
|||||||
|
|
||||||
// 128 bit resolution of the demurrage divisor
|
// 128 bit resolution of the demurrage divisor
|
||||||
// (this constant x 1000000 is contained within 128 bits)
|
// (this constant x 1000000 is contained within 128 bits)
|
||||||
uint256 constant nanoDivider = 100000000000000000000000000; // now nanodivider, 6 zeros less
|
//uint256 constant nanoDivider = 100000000000000000000000000; // now nanodivider, 6 zeros less
|
||||||
|
|
||||||
// remaining decimal positions of nanoDivider to reach 38, equals precision in growth and decay
|
// remaining decimal positions of nanoDivider to reach 38, equals precision in growth and decay
|
||||||
uint256 constant growthResolutionFactor = 1000000000000;
|
//uint256 constant growthResolutionFactor = 1000000000000;
|
||||||
|
|
||||||
// demurrage decimal width; 38 places
|
// demurrage decimal width; 38 places
|
||||||
uint256 public immutable resolutionFactor = nanoDivider * growthResolutionFactor;
|
//uint256 public immutable resolutionFactor = nanoDivider * growthResolutionFactor;
|
||||||
|
|
||||||
// Timestamp of start of periods (time which contract constructor was called)
|
// Timestamp of start of periods (time which contract constructor was called)
|
||||||
uint256 public immutable periodStart;
|
uint256 public immutable periodStart;
|
||||||
@ -64,7 +67,9 @@ contract DemurrageTokenSingleCap {
|
|||||||
uint256 public immutable periodDuration;
|
uint256 public immutable periodDuration;
|
||||||
|
|
||||||
// Demurrage in ppm per minute
|
// Demurrage in ppm per minute
|
||||||
uint256 public immutable taxLevel;
|
//uint256 public immutable taxLevel;
|
||||||
|
// 64x64
|
||||||
|
int128 public taxLevel;
|
||||||
|
|
||||||
// Addresses allowed to mint new tokens
|
// Addresses allowed to mint new tokens
|
||||||
mapping (address => bool) minter;
|
mapping (address => bool) minter;
|
||||||
@ -102,9 +107,12 @@ contract DemurrageTokenSingleCap {
|
|||||||
// EIP173
|
// EIP173
|
||||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
|
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
|
||||||
|
|
||||||
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint128 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress) public {
|
constructor(string memory _name, string memory _symbol, uint8 _decimals, int128 _taxLevel, uint256 _periodMinutes, address _defaultSinkAddress) {
|
||||||
|
require(_taxLevel < (1 << 64));
|
||||||
redistributionItem memory initialRedistribution;
|
redistributionItem memory initialRedistribution;
|
||||||
|
|
||||||
|
//require(ABDKMath64x64.toUInt(_taxLevel) == 0);
|
||||||
|
|
||||||
// ACL setup
|
// ACL setup
|
||||||
owner = msg.sender;
|
owner = msg.sender;
|
||||||
minter[owner] = true;
|
minter[owner] = true;
|
||||||
@ -118,9 +126,11 @@ contract DemurrageTokenSingleCap {
|
|||||||
demurrageTimestamp = block.timestamp;
|
demurrageTimestamp = block.timestamp;
|
||||||
periodStart = demurrageTimestamp;
|
periodStart = demurrageTimestamp;
|
||||||
periodDuration = _periodMinutes * 60;
|
periodDuration = _periodMinutes * 60;
|
||||||
demurrageAmount = uint128(nanoDivider) * 100;
|
demurrageAmount = ABDKMath64x64.fromUInt(1);
|
||||||
taxLevel = _taxLevelMinute; // Represents 38 decimal places
|
|
||||||
initialRedistribution = toRedistribution(0, demurrageAmount, 0, 1);
|
//taxLevel = ABDKMath64x64.mul(ABDKMath64x64.ln(ABDKMath64x64.sub(demurrageAmount, , ABDKMath64x64.fromUInt(_periodMinutes));
|
||||||
|
taxLevel = ABDKMath64x64.ln(_taxLevel);
|
||||||
|
initialRedistribution = toRedistribution(0, uint40(uint128(demurrageAmount)), 0, 1);
|
||||||
redistributions.push(initialRedistribution);
|
redistributions.push(initialRedistribution);
|
||||||
|
|
||||||
// Misc settings
|
// Misc settings
|
||||||
@ -150,20 +160,21 @@ contract DemurrageTokenSingleCap {
|
|||||||
|
|
||||||
/// Implements ERC20
|
/// Implements ERC20
|
||||||
function balanceOf(address _account) public view returns (uint256) {
|
function balanceOf(address _account) public view returns (uint256) {
|
||||||
uint256 baseBalance;
|
int128 baseBalance;
|
||||||
uint256 currentDemurragedAmount;
|
int128 currentDemurragedAmount;
|
||||||
uint256 periodCount;
|
uint256 periodCount;
|
||||||
|
|
||||||
baseBalance = baseBalanceOf(_account);
|
baseBalance = ABDKMath64x64.fromUInt(baseBalanceOf(_account));
|
||||||
|
|
||||||
periodCount = getMinutesDelta(demurrageTimestamp);
|
periodCount = getMinutesDelta(demurrageTimestamp);
|
||||||
|
|
||||||
currentDemurragedAmount = uint128(decayBy(demurrageAmount * 10000000000, periodCount));
|
currentDemurragedAmount = ABDKMath64x64.mul(baseBalance, demurrageAmount);
|
||||||
|
return decayBy(ABDKMath64x64.toUInt(currentDemurragedAmount), periodCount);
|
||||||
|
|
||||||
return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
|
//return (baseBalance * currentDemurragedAmount) / (nanoDivider * 1000000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Balance unmodified by demurrage
|
// Balance unmodified by demurrage
|
||||||
function baseBalanceOf(address _account) public view returns (uint256) {
|
function baseBalanceOf(address _account) public view returns (uint256) {
|
||||||
return account[_account];
|
return account[_account];
|
||||||
}
|
}
|
||||||
@ -210,7 +221,7 @@ contract DemurrageTokenSingleCap {
|
|||||||
|
|
||||||
require(minter[msg.sender], 'ERR_ACCESS');
|
require(minter[msg.sender], 'ERR_ACCESS');
|
||||||
|
|
||||||
changePeriod();
|
//changePeriod();
|
||||||
baseAmount = toBaseAmount(_amount);
|
baseAmount = toBaseAmount(_amount);
|
||||||
supply += _amount;
|
supply += _amount;
|
||||||
increaseBaseBalance(_beneficiary, baseAmount);
|
increaseBaseBalance(_beneficiary, baseAmount);
|
||||||
@ -225,7 +236,7 @@ contract DemurrageTokenSingleCap {
|
|||||||
|
|
||||||
redistribution.period = uint32(_period);
|
redistribution.period = uint32(_period);
|
||||||
redistribution.value = uint72(_value);
|
redistribution.value = uint72(_value);
|
||||||
redistribution.demurrage = uint104(_demurrageModifierPpm);
|
redistribution.demurrage = uint40(_demurrageModifierPpm);
|
||||||
return redistribution;
|
return redistribution;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -269,81 +280,81 @@ contract DemurrageTokenSingleCap {
|
|||||||
return uint128((block.timestamp - periodStart) / periodDuration + 1);
|
return uint128((block.timestamp - periodStart) / periodDuration + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve next redistribution if the period threshold has been crossed
|
// // Retrieve next redistribution if the period threshold has been crossed
|
||||||
function checkPeriod() private view returns (redistributionItem memory) {
|
// function checkPeriod() private view returns (redistributionItem memory) {
|
||||||
redistributionItem memory lastRedistribution;
|
// redistributionItem memory lastRedistribution;
|
||||||
redistributionItem memory emptyRedistribution;
|
// redistributionItem memory emptyRedistribution;
|
||||||
uint256 currentPeriod;
|
// uint256 currentPeriod;
|
||||||
|
//
|
||||||
|
// lastRedistribution = redistributions[lastPeriod];
|
||||||
|
// currentPeriod = this.actualPeriod();
|
||||||
|
// if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
|
||||||
|
// return emptyRedistribution;
|
||||||
|
// }
|
||||||
|
// return lastRedistribution;
|
||||||
|
// }
|
||||||
|
|
||||||
lastRedistribution = redistributions[lastPeriod];
|
// function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
|
||||||
currentPeriod = this.actualPeriod();
|
// uint256 difference;
|
||||||
if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) {
|
//
|
||||||
return emptyRedistribution;
|
// difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000));
|
||||||
}
|
// return difference / resolutionFactor;
|
||||||
return lastRedistribution;
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
function getDistribution(uint256 _supply, uint256 _demurrageAmount) public view returns (uint256) {
|
// function getDistributionFromRedistribution(redistributionItem memory _redistribution) public returns (uint256) {
|
||||||
uint256 difference;
|
// uint256 redistributionSupply;
|
||||||
|
// uint256 redistributionDemurrage;
|
||||||
difference = _supply * (resolutionFactor - (_demurrageAmount * 10000000000));
|
//
|
||||||
return difference / resolutionFactor;
|
// redistributionSupply = toRedistributionSupply(_redistribution);
|
||||||
}
|
// redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
|
||||||
|
// return getDistribution(redistributionSupply, redistributionDemurrage);
|
||||||
function getDistributionFromRedistribution(redistributionItem memory _redistribution) public returns (uint256) {
|
// }
|
||||||
uint256 redistributionSupply;
|
//
|
||||||
uint256 redistributionDemurrage;
|
// // Returns the amount sent to the sink address
|
||||||
|
// function applyDefaultRedistribution(redistributionItem memory _redistribution) private returns (uint256) {
|
||||||
redistributionSupply = toRedistributionSupply(_redistribution);
|
// uint256 unit;
|
||||||
redistributionDemurrage = toRedistributionDemurrageModifier(_redistribution);
|
// uint256 baseUnit;
|
||||||
return getDistribution(redistributionSupply, redistributionDemurrage);
|
//
|
||||||
}
|
// unit = getDistributionFromRedistribution(_redistribution);
|
||||||
|
// baseUnit = toBaseAmount(unit) - totalSink;
|
||||||
// Returns the amount sent to the sink address
|
// increaseBaseBalance(sinkAddress, baseUnit);
|
||||||
function applyDefaultRedistribution(redistributionItem memory _redistribution) private returns (uint256) {
|
// lastPeriod += 1;
|
||||||
uint256 unit;
|
// totalSink += baseUnit;
|
||||||
uint256 baseUnit;
|
// return unit;
|
||||||
|
// }
|
||||||
unit = getDistributionFromRedistribution(_redistribution);
|
|
||||||
baseUnit = toBaseAmount(unit) - totalSink;
|
|
||||||
increaseBaseBalance(sinkAddress, baseUnit);
|
|
||||||
lastPeriod += 1;
|
|
||||||
totalSink += baseUnit;
|
|
||||||
return unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the time delta in whole minutes passed between given timestamp and current timestamp
|
// Calculate the time delta in whole minutes passed between given timestamp and current timestamp
|
||||||
function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) {
|
function getMinutesDelta(uint256 _lastTimestamp) public view returns (uint256) {
|
||||||
return (block.timestamp - _lastTimestamp) / 60;
|
return (block.timestamp - _lastTimestamp) / 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (bool) {
|
// function applyDemurrage() public returns (bool) {
|
||||||
return applyDemurrageLimited(0);
|
// return applyDemurrageLimited(0);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
|
// function applyDemurrageLimited(uint256 _rounds) public returns (bool) {
|
||||||
uint256 periodCount;
|
// uint256 periodCount;
|
||||||
uint256 lastDemurrageAmount;
|
// uint256 lastDemurrageAmount;
|
||||||
|
//
|
||||||
periodCount = getMinutesDelta(demurrageTimestamp);
|
// periodCount = getMinutesDelta(demurrageTimestamp);
|
||||||
if (periodCount == 0) {
|
// if (periodCount == 0) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
lastDemurrageAmount = demurrageAmount;
|
// lastDemurrageAmount = demurrageAmount;
|
||||||
|
//
|
||||||
// safety limit for exponential calculation to ensure that we can always
|
// // safety limit for exponential calculation to ensure that we can always
|
||||||
// execute this code no matter how much time passes.
|
// // execute this code no matter how much time passes.
|
||||||
if (_rounds > 0 && _rounds < periodCount) {
|
// if (_rounds > 0 && _rounds < periodCount) {
|
||||||
periodCount = _rounds;
|
// periodCount = _rounds;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
|
// demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount));
|
||||||
//demurragePeriod = epochPeriodCount;
|
// //demurragePeriod = epochPeriodCount;
|
||||||
demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
// demurrageTimestamp = demurrageTimestamp + (periodCount * 60);
|
||||||
emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
|
// emit Decayed(demurrageTimestamp, periodCount, lastDemurrageAmount, demurrageAmount);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Return timestamp of start of period threshold
|
// Return timestamp of start of period threshold
|
||||||
function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) {
|
function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) {
|
||||||
@ -368,155 +379,162 @@ contract DemurrageTokenSingleCap {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate the demurrage modifier for the new period
|
// // Recalculate the demurrage modifier for the new period
|
||||||
// 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.
|
// // 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.
|
||||||
function changePeriod() public returns (bool) {
|
// function changePeriod() public returns (bool) {
|
||||||
redistributionItem memory currentRedistribution;
|
// redistributionItem memory currentRedistribution;
|
||||||
redistributionItem memory nextRedistribution;
|
// redistributionItem memory nextRedistribution;
|
||||||
redistributionItem memory lastRedistribution;
|
// redistributionItem memory lastRedistribution;
|
||||||
uint256 currentPeriod;
|
// uint256 currentPeriod;
|
||||||
uint256 lastDemurrageAmount;
|
// uint256 lastDemurrageAmount;
|
||||||
uint256 nextRedistributionDemurrage;
|
// uint256 nextRedistributionDemurrage;
|
||||||
uint256 demurrageCounts;
|
// uint256 demurrageCounts;
|
||||||
uint256 nextPeriod;
|
// uint256 nextPeriod;
|
||||||
|
|
||||||
applyDemurrage();
|
|
||||||
currentRedistribution = checkPeriod();
|
|
||||||
if (isEmptyRedistribution(currentRedistribution)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate the decay from previous redistributino
|
|
||||||
lastRedistribution = redistributions[lastPeriod];
|
|
||||||
currentPeriod = toRedistributionPeriod(currentRedistribution);
|
|
||||||
nextPeriod = currentPeriod + 1;
|
|
||||||
lastDemurrageAmount = toRedistributionDemurrageModifier(lastRedistribution);
|
|
||||||
demurrageCounts = periodDuration / 60;
|
|
||||||
nextRedistributionDemurrage = decayBy(lastDemurrageAmount, demurrageCounts);
|
|
||||||
|
|
||||||
nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply(), nextPeriod);
|
|
||||||
redistributions.push(nextRedistribution);
|
|
||||||
|
|
||||||
applyDefaultRedistribution(nextRedistribution);
|
|
||||||
emit Period(nextPeriod);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse a value reduced by demurrage by the given period to its original value
|
|
||||||
// function growBy(uint256 _value, uint256 _period) public view returns (uint256) {
|
|
||||||
// uint256 valueFactor;
|
|
||||||
// uint256 truncatedTaxLevel;
|
|
||||||
//
|
|
||||||
// valueFactor = growthResolutionFactor;
|
|
||||||
// truncatedTaxLevel = taxLevel / nanoDivider;
|
|
||||||
//
|
//
|
||||||
// for (uint256 i = 0; i < _period; i++) {
|
// applyDemurrage();
|
||||||
// valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
|
// currentRedistribution = checkPeriod();
|
||||||
|
// if (isEmptyRedistribution(currentRedistribution)) {
|
||||||
|
// return false;
|
||||||
// }
|
// }
|
||||||
// return (valueFactor * _value) / growthResolutionFactor;
|
//
|
||||||
|
// // calculate the decay from previous redistributino
|
||||||
|
// lastRedistribution = redistributions[lastPeriod];
|
||||||
|
// currentPeriod = toRedistributionPeriod(currentRedistribution);
|
||||||
|
// nextPeriod = currentPeriod + 1;
|
||||||
|
// lastDemurrageAmount = toRedistributionDemurrageModifier(lastRedistribution);
|
||||||
|
// demurrageCounts = periodDuration / 60;
|
||||||
|
// nextRedistributionDemurrage = decayBy(lastDemurrageAmount, demurrageCounts);
|
||||||
|
//
|
||||||
|
// nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply(), nextPeriod);
|
||||||
|
// redistributions.push(nextRedistribution);
|
||||||
|
//
|
||||||
|
// applyDefaultRedistribution(nextRedistribution);
|
||||||
|
// emit Period(nextPeriod);
|
||||||
|
// return true;
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
// // Reverse a value reduced by demurrage by the given period to its original value
|
||||||
|
//// function growBy(uint256 _value, uint256 _period) public view returns (uint256) {
|
||||||
|
//// uint256 valueFactor;
|
||||||
|
//// uint256 truncatedTaxLevel;
|
||||||
|
////
|
||||||
|
//// valueFactor = growthResolutionFactor;
|
||||||
|
//// truncatedTaxLevel = taxLevel / nanoDivider;
|
||||||
|
////
|
||||||
|
//// for (uint256 i = 0; i < _period; i++) {
|
||||||
|
//// valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
|
||||||
|
//// }
|
||||||
|
//// return (valueFactor * _value) / growthResolutionFactor;
|
||||||
|
//// }
|
||||||
|
|
||||||
// Calculate a value reduced by demurrage by the given period
|
// Calculate a value reduced by demurrage by the given period
|
||||||
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {
|
function decayBy(uint256 _value, uint256 _period) public view returns (uint256) {
|
||||||
uint256 valueFactor;
|
int128 valuePoint;
|
||||||
uint256 truncatedTaxLevel;
|
int128 periodPoint;
|
||||||
|
int128 v;
|
||||||
valueFactor = growthResolutionFactor;
|
|
||||||
truncatedTaxLevel = taxLevel / nanoDivider;
|
valuePoint = ABDKMath64x64.fromUInt(_value);
|
||||||
|
periodPoint = ABDKMath64x64.fromUInt(_period);
|
||||||
|
|
||||||
for (uint256 i = 0; i < _period; i++) {
|
//valuePoint -= ABDKMath64x64.mul(ABDKMath64x64.exp(ABDKMath64x64.mul(taxLevel, periodPoint)), valuePoint);
|
||||||
valueFactor = valueFactor - ((valueFactor * truncatedTaxLevel) / growthResolutionFactor);
|
//valuePoint -= ABDKMath64x64.exp(ABDKMath64x64.mul(taxLevel, periodPoint));
|
||||||
}
|
v = ABDKMath64x64.mul(taxLevel, periodPoint);
|
||||||
return (valueFactor * _value) / growthResolutionFactor;
|
v = ABDKMath64x64.exp(v);
|
||||||
|
v = ABDKMath64x64.mul(valuePoint, v);
|
||||||
|
return ABDKMath64x64.toUInt(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Inflates the given amount according to the current demurrage modifier
|
// Inflates the given amount according to the current demurrage modifier
|
||||||
function toBaseAmount(uint256 _value) public view returns (uint256) {
|
function toBaseAmount(uint256 _value) public view returns (uint256) {
|
||||||
return (_value * resolutionFactor) / (demurrageAmount * 10000000000);
|
int128 r;
|
||||||
}
|
//return (_value * resolutionFactor) / (demurrageAmount * 10000000000);
|
||||||
|
r = ABDKMath64x64.mul(demurrageAmount, ABDKMath64x64.fromUInt(_value));
|
||||||
// Implements ERC20, triggers tax and/or redistribution
|
return ABDKMath64x64.toUInt(r);
|
||||||
function approve(address _spender, uint256 _value) public returns (bool) {
|
|
||||||
uint256 baseValue;
|
|
||||||
|
|
||||||
if (allowance[msg.sender][_spender] > 0) {
|
|
||||||
require(_value == 0, 'ZERO_FIRST');
|
|
||||||
}
|
|
||||||
|
|
||||||
changePeriod();
|
|
||||||
|
|
||||||
baseValue = toBaseAmount(_value);
|
|
||||||
allowance[msg.sender][_spender] = baseValue;
|
|
||||||
emit Approval(msg.sender, _spender, _value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce allowance by amount
|
|
||||||
function decreaseAllowance(address _spender, uint256 _value) public returns (bool) {
|
|
||||||
uint256 baseValue;
|
|
||||||
|
|
||||||
baseValue = toBaseAmount(_value);
|
|
||||||
require(allowance[msg.sender][_spender] >= baseValue);
|
|
||||||
|
|
||||||
changePeriod();
|
|
||||||
|
|
||||||
allowance[msg.sender][_spender] -= baseValue;
|
|
||||||
emit Approval(msg.sender, _spender, allowance[msg.sender][_spender]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increase allowance by amount
|
|
||||||
function increaseAllowance(address _spender, uint256 _value) public returns (bool) {
|
|
||||||
uint256 baseValue;
|
|
||||||
|
|
||||||
changePeriod();
|
|
||||||
|
|
||||||
baseValue = toBaseAmount(_value);
|
|
||||||
|
|
||||||
allowance[msg.sender][_spender] += baseValue;
|
|
||||||
emit Approval(msg.sender, _spender, allowance[msg.sender][_spender]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements ERC20, triggers tax and/or redistribution
|
|
||||||
function transfer(address _to, uint256 _value) public returns (bool) {
|
|
||||||
uint256 baseValue;
|
|
||||||
bool result;
|
|
||||||
|
|
||||||
changePeriod();
|
|
||||||
|
|
||||||
baseValue = toBaseAmount(_value);
|
|
||||||
result = transferBase(msg.sender, _to, baseValue);
|
|
||||||
emit Transfer(msg.sender, _to, _value);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements ERC20, triggers tax and/or redistribution
|
|
||||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
|
|
||||||
uint256 baseValue;
|
|
||||||
bool result;
|
|
||||||
|
|
||||||
changePeriod();
|
|
||||||
|
|
||||||
baseValue = toBaseAmount(_value);
|
|
||||||
require(allowance[_from][msg.sender] >= baseValue);
|
|
||||||
|
|
||||||
allowance[_from][msg.sender] -= baseValue;
|
|
||||||
result = transferBase(_from, _to, baseValue);
|
|
||||||
|
|
||||||
emit Transfer(_from, _to, _value);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ERC20 transfer backend for transfer, transferFrom
|
|
||||||
function transferBase(address _from, address _to, uint256 _value) private returns (bool) {
|
|
||||||
uint256 period;
|
|
||||||
|
|
||||||
decreaseBaseBalance(_from, _value);
|
|
||||||
increaseBaseBalance(_to, _value);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// // Implements ERC20, triggers tax and/or redistribution
|
||||||
|
// function approve(address _spender, uint256 _value) public returns (bool) {
|
||||||
|
// uint256 baseValue;
|
||||||
|
//
|
||||||
|
// if (allowance[msg.sender][_spender] > 0) {
|
||||||
|
// require(_value == 0, 'ZERO_FIRST');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// changePeriod();
|
||||||
|
//
|
||||||
|
// baseValue = toBaseAmount(_value);
|
||||||
|
// allowance[msg.sender][_spender] = baseValue;
|
||||||
|
// emit Approval(msg.sender, _spender, _value);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Reduce allowance by amount
|
||||||
|
// function decreaseAllowance(address _spender, uint256 _value) public returns (bool) {
|
||||||
|
// uint256 baseValue;
|
||||||
|
//
|
||||||
|
// baseValue = toBaseAmount(_value);
|
||||||
|
// require(allowance[msg.sender][_spender] >= baseValue);
|
||||||
|
//
|
||||||
|
// changePeriod();
|
||||||
|
//
|
||||||
|
// allowance[msg.sender][_spender] -= baseValue;
|
||||||
|
// emit Approval(msg.sender, _spender, allowance[msg.sender][_spender]);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Increase allowance by amount
|
||||||
|
// function increaseAllowance(address _spender, uint256 _value) public returns (bool) {
|
||||||
|
// uint256 baseValue;
|
||||||
|
//
|
||||||
|
// changePeriod();
|
||||||
|
//
|
||||||
|
// baseValue = toBaseAmount(_value);
|
||||||
|
//
|
||||||
|
// allowance[msg.sender][_spender] += baseValue;
|
||||||
|
// emit Approval(msg.sender, _spender, allowance[msg.sender][_spender]);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Implements ERC20, triggers tax and/or redistribution
|
||||||
|
// function transfer(address _to, uint256 _value) public returns (bool) {
|
||||||
|
// uint256 baseValue;
|
||||||
|
// bool result;
|
||||||
|
//
|
||||||
|
// changePeriod();
|
||||||
|
//
|
||||||
|
// baseValue = toBaseAmount(_value);
|
||||||
|
// result = transferBase(msg.sender, _to, baseValue);
|
||||||
|
// emit Transfer(msg.sender, _to, _value);
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Implements ERC20, triggers tax and/or redistribution
|
||||||
|
// function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
|
||||||
|
// uint256 baseValue;
|
||||||
|
// bool result;
|
||||||
|
//
|
||||||
|
// changePeriod();
|
||||||
|
//
|
||||||
|
// baseValue = toBaseAmount(_value);
|
||||||
|
// require(allowance[_from][msg.sender] >= baseValue);
|
||||||
|
//
|
||||||
|
// allowance[_from][msg.sender] -= baseValue;
|
||||||
|
// result = transferBase(_from, _to, baseValue);
|
||||||
|
//
|
||||||
|
// emit Transfer(_from, _to, _value);
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ERC20 transfer backend for transfer, transferFrom
|
||||||
|
// function transferBase(address _from, address _to, uint256 _value) private returns (bool) {
|
||||||
|
// uint256 period;
|
||||||
|
//
|
||||||
|
// decreaseBaseBalance(_from, _value);
|
||||||
|
// increaseBaseBalance(_to, _value);
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
// Implements EIP173
|
// Implements EIP173
|
||||||
function transferOwnership(address _newOwner) public returns (bool) {
|
function transferOwnership(address _newOwner) public returns (bool) {
|
||||||
@ -542,7 +560,7 @@ contract DemurrageTokenSingleCap {
|
|||||||
require(_value <= account[msg.sender]);
|
require(_value <= account[msg.sender]);
|
||||||
uint256 _delta = toBaseAmount(_value);
|
uint256 _delta = toBaseAmount(_value);
|
||||||
|
|
||||||
applyDemurrage();
|
//applyDemurrage();
|
||||||
decreaseBaseBalance(msg.sender, _delta);
|
decreaseBaseBalance(msg.sender, _delta);
|
||||||
burned += _value;
|
burned += _value;
|
||||||
emit Burn(msg.sender, _value);
|
emit Burn(msg.sender, _value);
|
||||||
|
|||||||
@ -15,8 +15,8 @@ multi_cap:
|
|||||||
multi: multi_nocap multi_cap
|
multi: multi_nocap multi_cap
|
||||||
|
|
||||||
single_nocap:
|
single_nocap:
|
||||||
$(SOLC) DemurrageTokenSingleNocap.sol --abi --evm-version byzantium | awk 'NR>3' > DemurrageTokenSingleNocap.json
|
$(SOLC) DemurrageTokenSingleNocap.sol --abi --evm-version byzantium | awk 'NR==4' > DemurrageTokenSingleNocap.json
|
||||||
$(SOLC) DemurrageTokenSingleNocap.sol --bin --evm-version byzantium | awk 'NR>3' > DemurrageTokenSingleNocap.bin
|
$(SOLC) DemurrageTokenSingleNocap.sol --bin --evm-version byzantium | awk 'NR==4' > DemurrageTokenSingleNocap.bin
|
||||||
truncate -s -1 DemurrageTokenSingleNocap.bin
|
truncate -s -1 DemurrageTokenSingleNocap.bin
|
||||||
|
|
||||||
single_cap:
|
single_cap:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user