commit 1a2b3bab370a01197aa043961c501b267df9e3c3
parent 8e60539245e230e4c8e7bd0c1901fe2744f0f256
Author: nolash <dev@holbrook.no>
Date: Tue, 2 Feb 2021 16:10:21 +0100
Add transfer, mint
Diffstat:
2 files changed, 151 insertions(+), 16 deletions(-)
diff --git a/python/tests/test_basic.py b/python/tests/test_basic.py
@@ -22,6 +22,7 @@ TAX_LEVEL = 10000 * 2 # 2%
#PERIOD = int(60/BLOCKTIME) * 60 * 24 * 30 # month
PERIOD = 2
+
class Test(unittest.TestCase):
contract = None
@@ -55,26 +56,103 @@ class Test(unittest.TestCase):
pass
+ @unittest.skip('foo')
def test_period(self):
self.assertEqual(self.contract.functions.actualPeriod().call(), 0)
self.eth_tester.mine_blocks(PERIOD)
self.assertEqual(self.contract.functions.actualPeriod().call(), 1)
+
+ @unittest.skip('foo')
+ def test_mint(self):
+ tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1024).transact();
+ r = self.w3.eth.getTransactionReceipt(tx_hash);
+ self.assertEqual(r.status, 1);
+
+ balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call();
+ self.assertEqual(balance, 1024);
+
+ tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 976).transact();
+ r = self.w3.eth.getTransactionReceipt(tx_hash);
+ self.assertEqual(r.status, 1);
+
+ balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call();
+ self.assertEqual(balance, 2000);
+
+
+ def test_transfer(self):
+ tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1024).transact();
+ r = self.w3.eth.getTransactionReceipt(tx_hash);
+ self.assertEqual(r.status, 1);
+
+ tx_hash = self.contract.functions.transfer(self.w3.eth.accounts[2], 500).transact({'from': self.w3.eth.accounts[1]});
+ r = self.w3.eth.getTransactionReceipt(tx_hash);
+ self.assertEqual(r.status, 1);
+
+ balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call();
+ self.assertEqual(balance_alice, 524);
+
+ balance_bob = self.contract.functions.balanceOf(self.w3.eth.accounts[2]).call();
+ self.assertEqual(balance_bob, 500);
+
+
+ @unittest.skip('foo')
def test_apply_tax(self):
- tx = self.contract.functions.noop().buildTransaction()
- logg.debug('gas {}'.format(self.w3.eth.estimateGas(tx)))
+ self.eth_tester.mine_blocks(PERIOD)
+ tx_hash = self.contract.functions.applyTax().transact()
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(self.contract.functions.redistributionCount().call(), 2)
+ self.assertEqual(self.contract.functions.demurrageModifier().call(), 980000)
self.eth_tester.mine_blocks(PERIOD)
- tx_hash = self.contract.functions.applyTax().transact();
- r = self.w3.eth.getTransactionReceipt(tx_hash);
- self.assertEqual(self.contract.functions.redistributionCount().call(), 2);
- self.assertEqual(self.contract.functions.demurrageModifier().call(), TAX_LEVEL);
+ tx_hash = self.contract.functions.applyTax().transact()
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(self.contract.functions.redistributionCount().call(), 3)
+ self.assertEqual(self.contract.functions.demurrageModifier().call(), 960400)
+
+
+ @unittest.skip('foo')
+ def test_tax_balance(self):
+ tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1000).transact()
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(r.status, 1)
self.eth_tester.mine_blocks(PERIOD)
- tx_hash = self.contract.functions.applyTax().transact();
- r = self.w3.eth.getTransactionReceipt(tx_hash);
- self.assertEqual(self.contract.functions.redistributionCount().call(), 3);
- self.assertEqual(self.contract.functions.demurrageModifier().call(), TAX_LEVEL * 2);
+ tx_hash = self.contract.functions.applyTax().transact()
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(r.status, 1)
+
+ balance = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
+ self.assertEqual(balance, 980)
+
+
+ def test_taxed_transfer(self):
+ tx_hash = self.contract.functions.mintTo(self.w3.eth.accounts[1], 1000000).transact()
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(r.status, 1)
+
+ self.eth_tester.mine_blocks(PERIOD)
+ tx_hash = self.contract.functions.applyTax().transact()
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(r.status, 1)
+
+ balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
+ self.assertEqual(balance_alice, 980000);
+
+ tx_hash = self.contract.functions.transfer(self.w3.eth.accounts[2], 500000).transact({'from': self.w3.eth.accounts[1]})
+ r = self.w3.eth.getTransactionReceipt(tx_hash)
+ self.assertEqual(r.status, 1)
+
+ balance_alice = self.contract.functions.balanceOf(self.w3.eth.accounts[1]).call()
+ balance_alice_trunc = int(balance_alice/1000)*1000
+ self.assertEqual(balance_alice_trunc, 480000)
+
+ balance_bob = self.contract.functions.balanceOf(self.w3.eth.accounts[2]).call()
+ balance_bob_trunc = int(balance_bob/1000)*1000
+ self.assertEqual(balance_bob_trunc, 500000)
+
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/solidity/RedistributedDemurrageToken.sol b/solidity/RedistributedDemurrageToken.sol
@@ -12,26 +12,70 @@ contract RedistributedDemurrageToken {
uint256 public periodStart;
uint256 public periodDuration;
- uint32 public taxLevel;
- uint256 public demurrageModifier;
+ uint256 public taxLevel; // PPM
+ uint256 public demurrageModifier; // PPM
bytes32[] redistributions; // uint40(participants) uint160(value) uint56(period)
+ mapping (address => bytes32) account;
+ mapping (address => bool) minter;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
+ event Mint(address indexed _minter, address indexed _beneficiary, uint256 _amount);
constructor(string memory _name, string memory _symbol, uint32 _taxLevel, uint256 _period) {
owner = msg.sender;
+ minter[owner] = true;
periodStart = block.number;
periodDuration = _period;
taxLevel = _taxLevel;
name = _name;
symbol = _symbol;
decimals = 6;
+ demurrageModifier = 1000000;
bytes32 initialRedistribution = toRedistribution(0, 1, 0);
redistributions.push(initialRedistribution);
}
+ function addMinter(address _minter) public returns (bool) {
+ require(msg.sender == owner);
+ minter[_minter] = true;
+ return true;
+ }
+
+ function balanceOf(address _account) public view returns (uint256) {
+ uint256 baseBalance = getBaseBalance(_account);
+ uint256 inverseModifier = 1000000 - demurrageModifier;
+ uint256 balanceModifier = (inverseModifier * baseBalance) / 1000000;
+ return baseBalance - balanceModifier;
+ }
+
+ function getBaseBalance(address _account) private view returns (uint256) {
+ return uint256(account[_account]) & 0x00ffffffffffffffffffffffffffffffffffffffff;
+ }
+
+ function increaseBalance(address _account, uint256 _delta) private returns (bool) {
+ uint256 oldBalance = getBaseBalance(_account);
+ account[_account] &= bytes20(0x00);
+ account[_account] |= bytes32((oldBalance + _delta) & 0x00ffffffffffffffffffffffffffffffffffffffff);
+ return true;
+ }
+
+ function decreaseBalance(address _account, uint256 _delta) private returns (bool) {
+ uint256 oldBalance = getBaseBalance(_account);
+ account[_account] &= bytes20(0x00);
+ account[_account] |= bytes32((oldBalance - _delta) & 0x00ffffffffffffffffffffffffffffffffffffffff);
+ return true;
+ }
+
+ function mintTo(address _beneficiary, uint256 _amount) external returns (bool) {
+ require(minter[msg.sender]);
+
+ increaseBalance(_beneficiary, _amount);
+ emit Mint(msg.sender, _beneficiary, _amount);
+ return true;
+ }
+
function toRedistribution(uint256 _participants, uint256 _value, uint256 _period) private pure returns(bytes32) {
bytes32 redistribution;
redistribution |= bytes32((_participants & 0xffffffffff) << 215);
@@ -64,18 +108,31 @@ contract RedistributedDemurrageToken {
function applyTax() public returns (uint256) {
bytes32 pendingRedistribution;
bytes32 nextRedistribution;
+ uint256 currentPeriod;
pendingRedistribution = checkPeriod();
if (pendingRedistribution == bytes32(0x00)) {
return demurrageModifier;
}
- demurrageModifier += taxLevel;
- nextRedistribution = toRedistribution(0, actualPeriod(), 0);
+ demurrageModifier -= (demurrageModifier * taxLevel) / 1000000;
+ // this should increment for one single period at at time
+ currentPeriod = toRedistributionPeriod(pendingRedistribution);
+ nextRedistribution = toRedistribution(0, currentPeriod + 1, 0);
redistributions.push(nextRedistribution);
return demurrageModifier;
}
- function noop() public returns (uint256) {
- return 0;
+ function transfer(address _to, uint256 _value) public returns (bool ) {
+ //&uint256 baseValue = (_value * 1000000) / demurrageModifier;
+ uint256 baseValue = (_value * 1000000) / demurrageModifier;
+ bool result = transferBase(_to, baseValue);
+ emit Transfer(msg.sender, _to, _value);
+ return result;
+ }
+
+ function transferBase(address _to, uint256 _value) private returns (bool) {
+ decreaseBalance(msg.sender, _value);
+ increaseBalance(_to, _value);
+ return true;
}
}