From 70c62c06fe7af325028b15b7ee42f77419583af0 Mon Sep 17 00:00:00 2001 From: Ville Sundell Date: Fri, 15 Feb 2019 19:59:41 +0200 Subject: [PATCH] TokenVault: Implementing full EIP-20 support and improved tests Previously we had a check for isToken() interface function. The check is important for testing if the token is correct. However, not all of the EIP-20 tokens support such a check. Therefore, modified the check to check totalSupply instead. 0 supply is permitted, for example the token could be minted afterwards. Also, there were no tests for this check, added those. --- contracts/TokenVault.sol | 11 ++--- ico/tests/contracts/test_token_vault.py | 63 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/contracts/TokenVault.sol b/contracts/TokenVault.sol index 8aad5986..fcda013f 100644 --- a/contracts/TokenVault.sol +++ b/contracts/TokenVault.sol @@ -9,7 +9,7 @@ pragma solidity ^0.4.8; import "./Recoverable.sol"; import "./SafeMathLib.sol"; -import "./StandardTokenExt.sol"; +import "zeppelin/contracts/token/ERC20/ERC20.sol"; import "zeppelin/contracts/ownership/Ownable.sol"; /** @@ -62,7 +62,7 @@ contract TokenVault is Ownable, Recoverable { uint public tokensPerSecond; /** We can also define our own token, which will override the ICO one ***/ - StandardTokenExt public token; + ERC20 public token; /** What is our current state. * @@ -89,7 +89,7 @@ contract TokenVault is Ownable, Recoverable { * @param _tokensToBeAllocated Total number of tokens this vault will hold - including decimal multiplication * @param _tokensPerSecond Define the tap: how many tokens we permit an user to withdraw per second, 0 to disable */ - function TokenVault(address _owner, uint _freezeEndsAt, StandardTokenExt _token, uint _tokensToBeAllocated, uint _tokensPerSecond) { + function TokenVault(address _owner, uint _freezeEndsAt, ERC20 _token, uint _tokensToBeAllocated, uint _tokensPerSecond) { owner = _owner; @@ -101,9 +101,8 @@ contract TokenVault is Ownable, Recoverable { token = _token; // Check the address looks like a token contract - if(!token.isToken()) { - throw; - } + // ">=" is intentional: 0 is fine, we just want to check if the function is there + require(token.totalSupply() >= 0); // Give argument if(_freezeEndsAt == 0) { diff --git a/ico/tests/contracts/test_token_vault.py b/ico/tests/contracts/test_token_vault.py index e13fd738..a076f5cc 100644 --- a/ico/tests/contracts/test_token_vault.py +++ b/ico/tests/contracts/test_token_vault.py @@ -14,6 +14,11 @@ class TokenVaultState(enum.IntEnum): Distributing = 3 +@pytest.fixture +def zero_address() -> str: + return "0x0000000000000000000000000000000000000000" + + @pytest.fixture def token(chain, team_multisig): args = [ @@ -61,6 +66,13 @@ def token_vault_balances(chain, customer, customer_2) -> list: ] +@pytest.fixture +def non_token(chain, team_multisig, token, freeze_ends_at, token_vault_balances) -> Contract: + """A test fixture to deploy a non-token.""" + + contract, hash = chain.provider.deploy_contract('GasStipendTester') + return contract + @pytest.fixture def token_vault(chain, team_multisig, token, freeze_ends_at, token_vault_balances) -> Contract: """A test fixture to deploy a token vault.""" @@ -339,3 +351,54 @@ def test_tapped_claim(chain, token_vault_tapped, team_multisig, token, customer, assert token.functions.balanceOf(customer_2).call() == 2000 assert token_vault_tapped.functions.totalClaimed().call() == 2400 + + +def test_vault_nontoken(chain, team_multisig, non_token, freeze_ends_at, token_vault_balances) -> Contract: + """Testing how a non-token vault works.""" + + total = 1000 + 2000 + + args = [ + team_multisig, + freeze_ends_at, + non_token.address, + total, + 0 # Disable the tap + ] + + with pytest.raises(TransactionFailed): + contract, hash = chain.provider.deploy_contract('TokenVault', deploy_args=args) + + +def test_vault_external_account(chain, team_multisig, customer_2, freeze_ends_at, token_vault_balances) -> Contract: + """Testing how a non-token vault works.""" + + total = 1000 + 2000 + + args = [ + team_multisig, + freeze_ends_at, + customer_2, + total, + 0 # Disable the tap + ] + + with pytest.raises(TransactionFailed): + contract, hash = chain.provider.deploy_contract('TokenVault', deploy_args=args) + + +def test_vault_zero_address(chain, team_multisig, zero_address, freeze_ends_at, token_vault_balances) -> Contract: + """Testing how a non-token vault works.""" + + total = 1000 + 2000 + + args = [ + team_multisig, + freeze_ends_at, + zero_address, + total, + 0 # Disable the tap + ] + + with pytest.raises(TransactionFailed): + contract, hash = chain.provider.deploy_contract('TokenVault', deploy_args=args)