From bc6a2931701f299e46ca535140e1eefa9997add7 Mon Sep 17 00:00:00 2001 From: szotov Date: Tue, 26 Dec 2017 14:12:39 +0300 Subject: [PATCH] [KMS-ETH]- WalletManager updated to Escrow --- nkms_eth/project/contracts/Escrow.sol | 35 +-------- nkms_eth/project/contracts/WalletManager.sol | 52 ++++-------- tests/contracts/test_escrow.py | 40 +++------- tests/contracts/test_escrow_v2.py | 83 ++++++++------------ 4 files changed, 58 insertions(+), 152 deletions(-) diff --git a/nkms_eth/project/contracts/Escrow.sol b/nkms_eth/project/contracts/Escrow.sol index 8f0f5ceae..e3f8e07c5 100644 --- a/nkms_eth/project/contracts/Escrow.sol +++ b/nkms_eth/project/contracts/Escrow.sol @@ -89,7 +89,7 @@ contract Escrow is Miner, Ownable { require(_value <= token.balanceOf(address(this)) && _value <= info.value.sub(lockedTokens)); // Checks if tokens are not locked or lock can be increased - // TODO add checking reward + // TODO add checking amount of reward require(lockedTokens == 0 || info.releaseBlock >= block.number); if (lockedTokens == 0) { @@ -174,24 +174,9 @@ contract Escrow is Miner, Ownable { return getLockedTokens(_owner, block.number); } -// /** -// * @notice Get locked tokens value for all owners in a specified moment in time -// * @param _blockNumber Block number for checking -// **/ -// function getAllLockedTokens(uint256 _blockNumber) -// public constant returns (uint256 result) -// { -// var current = tokenOwners.step(0x0, true); -// while (current != 0x0) { -// result += getLockedTokens(current, _blockNumber); -// current = tokenOwners.step(current, true); -// } -// } - /** * @notice Get locked tokens value for all owners in current period **/ - // TODO use confirmed periods function getAllLockedTokens() public constant returns (uint256 result) { @@ -212,26 +197,8 @@ contract Escrow is Miner, Ownable { var releasePeriod = info.releaseBlock / blocksPerPeriod + 1; return block.number >= releasePeriod * blocksPerPeriod && info.numberConfirmedPeriods == 0; -// (info.numberConfirmedPeriods == 0 || -// info.confirmedPeriods[info.numberConfirmedPeriods - 1] > releasePeriod); } -// /** -// * @notice Penalize token owner -// * @param _user Token owner -// * @param _value Amount of tokens that will be confiscated -// **/ -// function penalize(address _user, uint256 _value) -// onlyOwner -// public returns (bool success) -// { -// require(getLockedTokens(_user) >= _value); -// tokenInfo[_user].value = tokenInfo[_user].value.sub(_value); -// tokenInfo[_user].lockedValue = tokenInfo[_user].lockedValue.sub(_value); -// token.burn(_value); -// return true; -// } - /** * @notice Confirm activity for future period **/ diff --git a/nkms_eth/project/contracts/WalletManager.sol b/nkms_eth/project/contracts/WalletManager.sol index 2a8e32b32..6e2d40052 100644 --- a/nkms_eth/project/contracts/WalletManager.sol +++ b/nkms_eth/project/contracts/WalletManager.sol @@ -88,7 +88,7 @@ contract WalletManager is Miner, Ownable { } require(_value <= token.balanceOf(wallet).sub(lockedTokens)); // Checks if tokens are not locked or lock can be increased - // TODO add checking reward + // TODO add checking amount of reward require(lockedTokens == 0 || wallet.releaseBlock() >= block.number); if (lockedTokens == 0) { @@ -134,20 +134,6 @@ contract WalletManager is Miner, Ownable { return wallets[_owner].getLockedTokens(_blockNumber); } - /** - * @notice Get locked tokens value for all owners in a specified moment in time - * @param _blockNumber Block number for checking - **/ - function getAllLockedTokens(uint256 _blockNumber) - public constant returns (uint256 result) - { - var current = walletOwners.step(0x0, true); - while (current != 0x0) { - result += getLockedTokens(current, _blockNumber); - current = walletOwners.step(current, true); - } - } - /** * @notice Get locked tokens value for owner * @param _owner Tokens owner @@ -159,27 +145,13 @@ contract WalletManager is Miner, Ownable { } /** - * @notice Get locked tokens value for all owners + * @notice Get locked tokens value for all owners in current period **/ function getAllLockedTokens() public constant returns (uint256 result) { - return getAllLockedTokens(block.number); - } - - /** - * @notice Penalize token owner - * @param _user Token owner - * @param _value Amount of tokens that will be confiscated - **/ - function penalize(address _user, uint256 _value) - onlyOwner - public returns (bool success) - { - require(walletOwners.valueExists(_user)); -// require(getLockedTokens(_user) >= _value); - wallets[_user].burn(_value); - return true; + var currentPeriod = block.number / blocksPerPeriod; + return lockedPerPeriod[currentPeriod].totalLockedValue; } /** @@ -196,8 +168,6 @@ contract WalletManager is Miner, Ownable { uint256 numberConfirmedPeriods = wallet.numberConfirmedPeriods(); return block.number >= releasePeriod * blocksPerPeriod && numberConfirmedPeriods == 0; -// (numberConfirmedPeriods == 0 || -// wallet.confirmedPeriods(numberConfirmedPeriods - 1) > releasePeriod); } /** @@ -281,6 +251,7 @@ contract WalletManager is Miner, Ownable { public constant returns (address o_stop, uint256 o_shift) { require(walletOwners.valueExists(_start)); + var currentPeriod = block.number / blocksPerPeriod; uint256 distance = 0; uint256 lockedTokens = 0; var current = _start; @@ -288,8 +259,17 @@ contract WalletManager is Miner, Ownable { if (current == 0x0) current = walletOwners.step(current, true); - while (true) { - lockedTokens = getLockedTokens(current); + while (current != 0x0) { + var wallet = wallets[current]; + var numberConfirmedPeriods = wallet.numberConfirmedPeriods(); + if (numberConfirmedPeriods == 0 || + wallet.confirmedPeriods(numberConfirmedPeriods - 1) != currentPeriod && + (numberConfirmedPeriods == 1 || + wallet.confirmedPeriods(numberConfirmedPeriods - 2) != currentPeriod)) { + current = walletOwners.step(current, true); + continue; + } + lockedTokens = wallet.lockedValue(); if (_delta < distance + lockedTokens) { o_stop = current; o_shift = _delta - distance; diff --git a/tests/contracts/test_escrow.py b/tests/contracts/test_escrow.py index c2c960604..87f583315 100644 --- a/tests/contracts/test_escrow.py +++ b/tests/contracts/test_escrow.py @@ -54,10 +54,8 @@ def test_escrow(web3, chain, token, escrow): chain.wait.for_receipt(tx) # Check that nothing is locked - # TODO fix getLockedTokens - assert escrow.call().getLockedTokens(ursula) == 0 - assert escrow.call().getLockedTokens(alice) == 0 - assert escrow.call().getAllLockedTokens() == 0 + assert 0 == escrow.call().getLockedTokens(ursula) + assert 0 == escrow.call().getLockedTokens(alice) # Ursula can't lock too low value # TODO uncomment @@ -107,30 +105,9 @@ def test_escrow(web3, chain, token, escrow): assert 1500 == token.call().balanceOf(escrow.address) assert 9000 == token.call().balanceOf(ursula) - # TODO complete penalize - # And can't penalize anyone - # with pytest.raises(TransactionFailed): - # tx = escrow.transact({'from': ursula}).penalize(ursula, 100) - # chain.wait.for_receipt(tx) - - # Creator can't penalize Ursula by burning tokens which exceeded her locked value - # with pytest.raises(TransactionFailed): - # tx = escrow.transact({'from': creator}).penalize(ursula, 1500) - # chain.wait.for_receipt(tx) - - # But can penalize Ursula by burning some locked tokens - # tx = escrow.transact({'from': creator}).penalize(ursula, 100) - # chain.wait.for_receipt(tx) - # assert 1400 == token.call().balanceOf(escrow.address) - # assert 900 == escrow.call().getLockedTokens(ursula) - # assert 1400 == escrow.call().getAllLockedTokens() - # assert 900 == escrow.call().tokenInfo(ursula)[0] - # Wait 100 blocks chain.wait.for_block(web3.eth.blockNumber + 100) assert 0 == escrow.call().getLockedTokens(ursula) - # TODO fix getLockedTokens - # assert 500 == escrow.call().getAllLockedTokens() # And Ursula can withdraw some tokens tx = escrow.transact({'from': ursula}).withdraw(100) @@ -253,6 +230,9 @@ def test_mining(web3, chain, token, escrow): tx = escrow.transact({'from': alice}).deposit(500, 200) chain.wait.for_receipt(tx) + # Using locked tokens starts from next period + assert 0 == escrow.call().getAllLockedTokens() + # Give rights for mining tx = token.transact({'from': creator}).addMiner(escrow.address) chain.wait.for_receipt(tx) @@ -265,6 +245,7 @@ def test_mining(web3, chain, token, escrow): # Ursula and Alice confirm next period chain.wait.for_block(web3.eth.blockNumber + 50) + assert 1500 == escrow.call().getAllLockedTokens() tx = escrow.transact({'from': ursula}).confirmActivity() chain.wait.for_receipt(tx) tx = escrow.transact({'from': alice}).confirmActivity() @@ -276,6 +257,7 @@ def test_mining(web3, chain, token, escrow): # Ursula can't confirm next period because end of locking chain.wait.for_block(web3.eth.blockNumber + 50) + assert 1500 == escrow.call().getAllLockedTokens() with pytest.raises(TransactionFailed): tx = escrow.transact({'from': ursula}).confirmActivity() chain.wait.for_receipt(tx) @@ -292,24 +274,22 @@ def test_mining(web3, chain, token, escrow): chain.wait.for_receipt(tx) assert 9033 == token.call().balanceOf(ursula) assert 9516 == token.call().balanceOf(alice) - # TODO fix - # assert 1500 == escrow.call().getAllLockedTokens() # Ursula and Alice mint tokens for next period chain.wait.for_block(web3.eth.blockNumber + 50) + assert 500 == escrow.call().getAllLockedTokens() tx = escrow.transact({'from': ursula}).mint() chain.wait.for_receipt(tx) tx = escrow.transact({'from': alice}).mint() chain.wait.for_receipt(tx) assert 9038 == token.call().balanceOf(ursula) assert 9532 == token.call().balanceOf(alice) - # TODO fix - # assert 500 == escrow.call().getAllLockedTokens() # Alice confirm 2 periods and mint tokens tx = escrow.transact({'from': alice}).confirmActivity() chain.wait.for_receipt(tx) chain.wait.for_block(web3.eth.blockNumber + 100) + assert 0 == escrow.call().getAllLockedTokens() tx = escrow.transact({'from': alice}).mint() chain.wait.for_receipt(tx) assert 9038 == token.call().balanceOf(ursula) @@ -317,8 +297,6 @@ def test_mining(web3, chain, token, escrow): alice_tokens = token.call().balanceOf(alice) assert alice_tokens < 9633 # max minted tokens assert alice_tokens > 9583 # min minted tokens - # TODO fix - # assert 0 == escrow.call().getAllLockedTokens() # Ursula can't confirm and mint because no locked tokens with pytest.raises(TransactionFailed): diff --git a/tests/contracts/test_escrow_v2.py b/tests/contracts/test_escrow_v2.py index e154a0961..07b768d38 100644 --- a/tests/contracts/test_escrow_v2.py +++ b/tests/contracts/test_escrow_v2.py @@ -32,8 +32,8 @@ def test_escrow(web3, chain, token, wallet_manager): chain.wait.for_receipt(tx) tx = token.transact({'from': creator}).transfer(alice, 10000) chain.wait.for_receipt(tx) - assert token.call().balanceOf(ursula) == 10000 - assert token.call().balanceOf(alice) == 10000 + assert 10000 == token.call().balanceOf(ursula) + assert 10000 == token.call().balanceOf(alice) # Ursula and Alice create wallets contract_factory = chain.provider.get_contract_factory("Wallet") @@ -62,17 +62,17 @@ def test_escrow(web3, chain, token, wallet_manager): # Ursula and Alice transfer some money to wallets tx = token.transact({'from': ursula}).transfer(ursula_wallet.address, 1500) chain.wait.for_receipt(tx) - assert token.call().balanceOf(ursula_wallet.address) == 1500 + assert 1500 == token.call().balanceOf(ursula_wallet.address) tx = token.transact({'from': alice}).transfer(alice_wallet.address, 500) chain.wait.for_receipt(tx) - assert token.call().balanceOf(alice_wallet.address) == 500 + assert 500 == token.call().balanceOf(alice_wallet.address) # Ursula asks for refund tx = ursula_wallet.transact({'from': ursula}).withdraw(500) chain.wait.for_receipt(tx) # and it works - assert token.call().balanceOf(ursula_wallet.address) == 1000 - assert token.call().balanceOf(ursula) == 9000 + assert 1000 == token.call().balanceOf(ursula_wallet.address) + assert 9000 == token.call().balanceOf(ursula) # Alice can't withdraw from Ursula's wallet with pytest.raises(TransactionFailed): @@ -80,9 +80,8 @@ def test_escrow(web3, chain, token, wallet_manager): chain.wait.for_receipt(tx) # Check that nothing is locked - assert ursula_wallet.call().getLockedTokens() == 0 - assert alice_wallet.call().getLockedTokens() == 0 - assert wallet_manager.call().getAllLockedTokens() == 0 + assert 0 == ursula_wallet.call().getLockedTokens() + assert 0 == alice_wallet.call().getLockedTokens() # Ursula can't lock too low value (less then rate) # TODO uncomment @@ -93,51 +92,31 @@ def test_escrow(web3, chain, token, wallet_manager): # Ursula and Alice lock some tokens for 100 and 200 blocks tx = wallet_manager.transact({'from': ursula}).lock(1000, 100) chain.wait.for_receipt(tx) - assert ursula_wallet.call().getLockedTokens() == 1000 - assert alice_wallet.call().getLockedTokens() == 0 - assert wallet_manager.call().getLockedTokens(ursula) == 1000 - assert wallet_manager.call().getAllLockedTokens() == 1000 tx = wallet_manager.transact({'from': alice}).lock(500, 200) chain.wait.for_receipt(tx) - assert ursula_wallet.call().getLockedTokens() == 1000 - assert alice_wallet.call().getLockedTokens() == 500 - assert wallet_manager.call().getLockedTokens(alice) == 500 - assert wallet_manager.call().getAllLockedTokens() == 1500 + + # Checks locked tokens in next period + chain.wait.for_block(web3.eth.blockNumber + 50) + assert 1000 == ursula_wallet.call().getLockedTokens() + assert 500 == alice_wallet.call().getLockedTokens() + assert 1500 == wallet_manager.call().getAllLockedTokens() # Ursula's withdrawal attempt won't succeed with pytest.raises(TransactionFailed): tx = ursula_wallet.transact({'from': ursula}).withdraw(100) chain.wait.for_receipt(tx) - assert token.call().balanceOf(ursula_wallet.address) == 1000 - assert token.call().balanceOf(ursula) == 9000 - - # And Ursula can't penalize anyone - with pytest.raises(TransactionFailed): - tx = wallet_manager.transact({'from': ursula}).penalize(ursula, 100) - chain.wait.for_receipt(tx) - - # Creator can't penalize Ursula by burning tokens which exceeded her locked value - with pytest.raises(TransactionFailed): - tx = wallet_manager.transact({'from': creator}).penalize(ursula, 2000) - chain.wait.for_receipt(tx) - - # But can penalize Ursula by burning some locked tokens - tx = wallet_manager.transact({'from': creator}).penalize(ursula, 100) - chain.wait.for_receipt(tx) - assert token.call().balanceOf(ursula_wallet.address) == 900 - assert ursula_wallet.call().getLockedTokens() == 900 - assert wallet_manager.call().getAllLockedTokens() == 1400 + assert 1000 == token.call().balanceOf(ursula_wallet.address) + assert 9000 == token.call().balanceOf(ursula) # Wait 100 blocks chain.wait.for_block(web3.eth.blockNumber + 100) - assert ursula_wallet.call().getLockedTokens() == 0 - assert wallet_manager.call().getAllLockedTokens() == 500 + assert 0 == ursula_wallet.call().getLockedTokens() # And Ursula can withdraw some tokens tx = ursula_wallet.transact({'from': ursula}).withdraw(100) chain.wait.for_receipt(tx) - assert token.call().balanceOf(ursula_wallet.address) == 800 - assert token.call().balanceOf(ursula) == 9100 + assert 900 == token.call().balanceOf(ursula_wallet.address) + assert 9100 == token.call().balanceOf(ursula) # But Ursula can't lock some of tokens again without mining for locked value with pytest.raises(TransactionFailed): @@ -149,14 +128,14 @@ def test_escrow(web3, chain, token, wallet_manager): chain.wait.for_receipt(tx) tx = wallet_manager.transact({'from': alice}).lock(500, 0) chain.wait.for_receipt(tx) - assert wallet_manager.call().getLockedTokens(alice) == 1000 - assert wallet_manager.call().getLockedTokens(alice, web3.eth.blockNumber + 100) == 0 + assert 1000 == wallet_manager.call().getLockedTokens(alice) + assert 0 == wallet_manager.call().getLockedTokens(alice, web3.eth.blockNumber + 100) # And increases locked blocks tx = wallet_manager.transact({'from': alice}).lock(0, 100) chain.wait.for_receipt(tx) - assert wallet_manager.call().getLockedTokens(alice) == 1000 - assert wallet_manager.call().getLockedTokens(alice, web3.eth.blockNumber + 100) == 1000 - assert wallet_manager.call().getLockedTokens(alice, web3.eth.blockNumber + 200) == 0 + assert 1000 == wallet_manager.call().getLockedTokens(alice) + assert 1000 == wallet_manager.call().getLockedTokens(alice, web3.eth.blockNumber + 100) + assert 0 == wallet_manager.call().getLockedTokens(alice, web3.eth.blockNumber + 200) # # Ursula can't destroy contract # TODO fix bug @@ -197,6 +176,7 @@ def test_locked_distribution(web3, chain, token, wallet_manager): tx = wallet_manager.transact({'from': addr}).lock(balance, 100) chain.wait.for_receipt(tx) + chain.wait.for_block(web3.eth.blockNumber + 50) n_locked = wallet_manager.call().getAllLockedTokens() assert n_locked > 0 @@ -256,6 +236,9 @@ def test_mining(web3, chain, token, wallet_manager): tx = wallet_manager.transact({'from': alice}).lock(500, 200) chain.wait.for_receipt(tx) + # Using locked tokens starts from next period + assert 0 == wallet_manager.call().getAllLockedTokens() + # Ursula can't use method from Miner contract with pytest.raises(TypeError): tx = wallet_manager.transact({'from': ursula}).mint(ursula, 1000, 1000, 1000, 1000) @@ -263,6 +246,7 @@ def test_mining(web3, chain, token, wallet_manager): # Ursula and Alice confirm next period chain.wait.for_block(web3.eth.blockNumber + 50) + assert 1500 == wallet_manager.call().getAllLockedTokens() tx = wallet_manager.transact({'from': ursula}).confirmActivity() chain.wait.for_receipt(tx) tx = wallet_manager.transact({'from': alice}).confirmActivity() @@ -279,6 +263,7 @@ def test_mining(web3, chain, token, wallet_manager): chain.wait.for_receipt(tx) # But Alice can + # TODO test situation when only one confirmed tx = wallet_manager.transact({'from': alice}).confirmActivity() chain.wait.for_receipt(tx) @@ -289,24 +274,22 @@ def test_mining(web3, chain, token, wallet_manager): chain.wait.for_receipt(tx) assert 1033 == token.call().balanceOf(ursula_wallet.address) assert 516 == token.call().balanceOf(alice_wallet.address) - # TODO fix - # assert 1500 == escrow.call().getAllLockedTokens() # Ursula and Alice mint tokens for next period chain.wait.for_block(web3.eth.blockNumber + 50) + assert 500 == wallet_manager.call().getAllLockedTokens() tx = wallet_manager.transact({'from': ursula}).mint() chain.wait.for_receipt(tx) tx = wallet_manager.transact({'from': alice}).mint() chain.wait.for_receipt(tx) assert 1040 == token.call().balanceOf(ursula_wallet.address) assert 532 == token.call().balanceOf(alice_wallet.address) - # TODO fix - # assert 500 == escrow.call().getAllLockedTokens() # Alice confirm 2 periods and mint tokens tx = wallet_manager.transact({'from': alice}).confirmActivity() chain.wait.for_receipt(tx) chain.wait.for_block(web3.eth.blockNumber + 100) + assert 0 == wallet_manager.call().getAllLockedTokens() tx = wallet_manager.transact({'from': alice}).mint() chain.wait.for_receipt(tx) assert 1040 == token.call().balanceOf(ursula_wallet.address) @@ -314,8 +297,6 @@ def test_mining(web3, chain, token, wallet_manager): alice_tokens = token.call().balanceOf(alice_wallet.address) assert alice_tokens < 633 # max minted tokens assert alice_tokens > 583 # min minted tokens - # TODO fix - # assert 0 == escrow.call().getAllLockedTokens() # Ursula can't confirm and mint because no locked tokens with pytest.raises(TransactionFailed):