From bc4c1ec1be6a37e784f7ba5c84b83fa3612c6590 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva Date: Mon, 21 Oct 2024 11:00:09 +0200 Subject: [PATCH] fix erc20ForSpl tests --- clickfile.py | 12 +- contracts/EIPs/ERC20/MultipleActions.sol | 18 ++- integration/tests/basic/erc/conftest.py | 4 +- integration/tests/basic/erc/test_ERC20SPL.py | 34 ++-- .../tests/basic/rpc/test_rpc_estimate_gas.py | 2 +- integration/tests/neon_evm/conftest.py | 34 +--- .../test_transaction_step_from_account.py | 13 +- utils/erc20wrapper.py | 145 +++++------------- 8 files changed, 81 insertions(+), 181 deletions(-) diff --git a/clickfile.py b/clickfile.py index 854d50a710..652933f937 100755 --- a/clickfile.py +++ b/clickfile.py @@ -524,13 +524,11 @@ def update_contracts(branch): download_evm_contracts(branch) update_contracts_from_git(HOODIES_CHAINLINK_GITHUB_URL, "hoodies_chainlink", "main") - contracts_branch = "main" - if is_branch_exist(NEON_CONTRACTS_GITHUB_URL, branch) and branch != "develop": - contracts_branch = branch - update_contracts_from_git( - NEON_CONTRACTS_REPO_URL, "neon-contracts", contracts_branch, update_npm=False - ) - subprocess.check_call(f'npm ci --prefix {EXTERNAL_CONTRACT_PATH / "neon-contracts" / "ERC20ForSPL"}', shell=True) + # uncomment for new version of erc20ForSpl + # update_contracts_from_git( + # f"https://github.com/{DOCKER_HUB_ORG_NAME}/neon-contracts.git", "neon-contracts", "main", update_npm=False + # ) + # subprocess.check_call(f'npm ci --prefix {EXTERNAL_CONTRACT_PATH / "neon-contracts" / "ERC20ForSPL"}', shell=True) @cli.command(help="Run any type of tests") diff --git a/contracts/EIPs/ERC20/MultipleActions.sol b/contracts/EIPs/ERC20/MultipleActions.sol index e476a900df..ecc8db598f 100644 --- a/contracts/EIPs/ERC20/MultipleActions.sol +++ b/contracts/EIPs/ERC20/MultipleActions.sol @@ -1,17 +1,23 @@ pragma solidity >=0.7.0; pragma abicoder v2; -import "../../external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPLMintable.sol"; -import "../../external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPLMintableFactory.sol"; +import "../../external/neon-evm/erc20_for_spl.sol"; contract MultipleActionsERC20 { uint256 data; - ERC20ForSPLMintable erc20; + ERC20ForSplMintable erc20; constructor( - address _token + string memory _name, + string memory _symbol, + uint8 _decimals ) { - erc20 = ERC20ForSPLMintable(_token); + erc20 = new ERC20ForSplMintable( + _name, + _symbol, + _decimals, + address(this) + ); } function balance(address who) public view returns (uint256) { @@ -127,4 +133,4 @@ contract MultipleActionsERC20 { erc20.transfer(transfer_to, mint_amount1); erc20.transfer(transfer_to, mint_amount2); } -} +} \ No newline at end of file diff --git a/integration/tests/basic/erc/conftest.py b/integration/tests/basic/erc/conftest.py index f0909f0ceb..b65d63295e 100644 --- a/integration/tests/basic/erc/conftest.py +++ b/integration/tests/basic/erc/conftest.py @@ -66,7 +66,7 @@ def multiple_actions_erc20(web3_client_session, accounts, erc20_spl_mintable): "0.8.24", accounts[0], contract_name="MultipleActionsERC20", - constructor_args=[erc20_spl_mintable.address], + constructor_args=[f"Test TTT", "TTT", 18], ) - erc20_spl_mintable.transfer_ownership(erc20_spl_mintable.account, contract.address) return accounts[0], contract + diff --git a/integration/tests/basic/erc/test_ERC20SPL.py b/integration/tests/basic/erc/test_ERC20SPL.py index 854537955f..a93568a088 100644 --- a/integration/tests/basic/erc/test_ERC20SPL.py +++ b/integration/tests/basic/erc/test_ERC20SPL.py @@ -101,7 +101,7 @@ def test_burn_more_than_exist( ): with pytest.raises( web3.exceptions.ContractLogicError, - match="0x96ab19c8", # AmountExceedsBalance error + match="burn amount exceeds balance", ): erc20_contract.burn(self.accounts[2], 1000) @@ -109,7 +109,7 @@ def test_burn_more_than_total_supply(self, erc20_contract): total = erc20_contract.contract.functions.totalSupply().call() with pytest.raises( web3.exceptions.ContractLogicError, - match="0x96ab19c8", # AmountExceedsBalance error + match="burn amount exceeds balance", ): erc20_contract.burn(erc20_contract.account, total + 1) @@ -136,7 +136,7 @@ def test_burnFrom_without_allowance(self, erc20_contract): new_account = self.accounts.create_account() with pytest.raises( web3.exceptions.ContractLogicError, - match="0x65ba6fc3", # InvalidAllowance error + match="insufficient allowance", ): erc20_contract.burn_from(new_account, erc20_contract.account.address, 10) @@ -146,7 +146,7 @@ def test_burnFrom_more_than_allowanced(self, erc20_contract): erc20_contract.approve(erc20_contract.account, new_account.address, amount) with pytest.raises( web3.exceptions.ContractLogicError, - match="0x65ba6fc3", # InvalidAllowance error + match="insufficient allowance", ): erc20_contract.burn_from(new_account, erc20_contract.account.address, amount + 1) @@ -173,7 +173,7 @@ def test_approve_more_than_total_supply(self, erc20_contract): ( ZERO_ADDRESS, web3.exceptions.ContractLogicError, - "0x7138356f", # EmptyAddress error + "approve to the zero address", ), ], ) @@ -219,7 +219,7 @@ def test_transfer(self, erc20_contract, restore_balance): ( ZERO_ADDRESS, web3.exceptions.ContractLogicError, - "0x7138356f", # EmptyAddress error + "transfer to the zero address", ), ], ) @@ -232,7 +232,7 @@ def test_transfer_more_than_balance(self, erc20_contract): balance = erc20_contract.contract.functions.balanceOf(erc20_contract.account.address).call() with pytest.raises( web3.exceptions.ContractLogicError, - match="0x96ab19c8", # AmountExceedsBalance error + match="transfer amount exceeds balance", ): erc20_contract.transfer(erc20_contract.account, erc20_contract.account.address, balance + 1) @@ -260,7 +260,7 @@ def test_transferFrom_without_allowance(self, erc20_contract): new_account = self.accounts.create_account() with pytest.raises( web3.exceptions.ContractLogicError, - match="0x65ba6fc3", # InvalidAllowance error + match="insufficient allowance", # InvalidAllowance error insufficient allowance ): erc20_contract.transfer_from( signer=new_account, @@ -275,7 +275,7 @@ def test_transferFrom_more_than_allowanced(self, erc20_contract): erc20_contract.approve(erc20_contract.account, new_account.address, amount) with pytest.raises( web3.exceptions.ContractLogicError, - match="0x65ba6fc3", # InvalidAllowance error + match="insufficient allowance", ): erc20_contract.transfer_from( signer=new_account, @@ -299,7 +299,7 @@ def test_transferFrom_more_than_balance(self, erc20_contract): erc20_contract.approve(erc20_contract.account, new_account.address, amount) with pytest.raises( web3.exceptions.ContractLogicError, - match="0x96ab19c8", # AmountExceedsBalance error + match="transfer amount exceeds balance", ): erc20_contract.transfer_from( signer=new_account, @@ -473,6 +473,7 @@ def restore_balance(self, erc20_spl_mintable): default_value - current_balance, ) + @pytest.mark.skip(reason="This test is not actual for erc20ForSpl 1.0.0") def test_owner(self, erc20_contract): owner = erc20_contract.contract.functions.owner().call() assert owner == erc20_contract.account.address @@ -482,6 +483,7 @@ def return_ownership(self, erc20_contract, accounts): yield erc20_contract.transfer_ownership(accounts[2], erc20_contract.account.address) + @pytest.mark.skip(reason="This test is not actual for erc20ForSpl 1.0.0") def test_transferOwnership(self, erc20_contract, accounts, return_ownership): erc20_contract.transfer_ownership(erc20_contract.account, accounts[2].address) owner = erc20_contract.contract.functions.owner().call() @@ -493,7 +495,6 @@ def test_metaplex_data(self, erc20_contract): metadata = metaplex.get_metadata(self.sol_client, mint_key) assert metadata["data"]["name"] == erc20_contract.name assert metadata["data"]["symbol"] == erc20_contract.symbol - assert metadata["data"]["uri"] == "http://uri.com" assert metadata["is_mutable"] is True def test_mint_to_self(self, erc20_contract, restore_balance): @@ -513,12 +514,8 @@ def test_mint_to_another_account(self, erc20_contract): def test_mint_by_no_minter_role(self, erc20_contract): recipient_account = self.accounts[1] - try: + with pytest.raises(web3.exceptions.ContractLogicError, match="must have minter role to mint"): erc20_contract.mint_tokens(recipient_account, recipient_account.address, 0) - except web3.exceptions.ContractLogicError as e: - assert "0x118cdaa7" in str(e) - else: - assert False, "No exception raised" @pytest.mark.parametrize( "address_to, expected_exception, msg", @@ -526,7 +523,7 @@ def test_mint_by_no_minter_role(self, erc20_contract): ( ZERO_ADDRESS, web3.exceptions.ContractLogicError, - "0x7138356f", # EmptyAddress error + "mint to the zero address", ), ], ) @@ -538,7 +535,7 @@ def test_mint_with_incorrect_address(self, erc20_contract, address_to, expected_ def test_mint_with_too_big_amount(self, erc20_contract): with pytest.raises( web3.exceptions.ContractLogicError, - match="0x679346bc", # AmountExceedsUint64 error + match="total mint amount exceeds uint64 max", ): erc20_contract.mint_tokens( erc20_contract.account, @@ -1008,6 +1005,7 @@ def new_token_contract(web3_client, erc20_spl_mintable): @allure.story("ERC20SPL: Tests for factory update") @pytest.mark.usefixtures("accounts", "web3_client", "sol_client") @pytest.mark.neon_only +@pytest.mark.skip(reason="This test is not actual for erc20ForSpl 1.0.0") class TestERC20FactoryUpdate: web3_client: NeonChainWeb3Client accounts: EthAccounts diff --git a/integration/tests/basic/rpc/test_rpc_estimate_gas.py b/integration/tests/basic/rpc/test_rpc_estimate_gas.py index 2b430f78c3..e2e6c41f86 100644 --- a/integration/tests/basic/rpc/test_rpc_estimate_gas.py +++ b/integration/tests/basic/rpc/test_rpc_estimate_gas.py @@ -132,7 +132,7 @@ def test_rpc_estimate_gas_spl(self, erc20_spl): assert "gas" in transaction estimated_gas = transaction["gas"] - assert estimated_gas == 2_089_280 + assert estimated_gas == 2_079_280 @pytest.mark.neon_only # Geth returns a different estimate def test_rpc_estimate_gas_contract_get_value(self, common_contract): diff --git a/integration/tests/neon_evm/conftest.py b/integration/tests/neon_evm/conftest.py index 0bb0e85c77..0e43c5464a 100644 --- a/integration/tests/neon_evm/conftest.py +++ b/integration/tests/neon_evm/conftest.py @@ -3,7 +3,6 @@ import eth_abi import pytest -from eth_utils import abi from solders.keypair import Keypair from eth_keys import keys as eth_keys from solders.pubkey import Pubkey @@ -176,43 +175,18 @@ def calculator_caller_contract( @pytest.fixture(scope="session") -def erc20_for_spl_proxy_contract( +def erc20_for_spl_factory_contract( operator_keypair, evm_loader, sender_with_tokens, treasury_pool, neon_api_client, holder_acc ): - contracts_path = "external/neon-contracts/ERC20ForSPL/contracts/" - beacon_erc20 = deploy_contract( - operator_keypair, - sender_with_tokens, - f"{contracts_path}ERC20ForSPLMintable", - evm_loader, - treasury_pool, - contract_name="ERC20ForSPLMintable", - version="0.8.24", - ) - - erc20_factory = deploy_contract( - operator_keypair, - sender_with_tokens, - f"{contracts_path}ERC20ForSPLMintableFactory", - evm_loader, - treasury_pool, - contract_name="ERC20ForSPLMintableFactory", - version="0.8.24", - ) - data = abi.function_signature_to_4byte_selector("initialize(address)") + eth_abi.encode( - ["address"], [f"0x{beacon_erc20.eth_address.hex()}"] - ) - proxy_contract = deploy_contract( + return deploy_contract( operator_keypair, sender_with_tokens, - f"{contracts_path}openzeppelin-fork/contracts/proxy/ERC1967/ERC1967Proxy", + "external/neon-evm/erc20_for_spl_factory", evm_loader, treasury_pool, - contract_name="ERC1967Proxy", + contract_name="ERC20ForSplFactory", version="0.8.24", - encoded_args=eth_abi.encode(["address", "bytes"], [f"0x{erc20_factory.eth_address.hex()}", data]), ) - return proxy_contract @pytest.fixture(scope="session") diff --git a/integration/tests/neon_evm/test_transaction_step_from_account.py b/integration/tests/neon_evm/test_transaction_step_from_account.py index 7901ba2386..b08d125b88 100644 --- a/integration/tests/neon_evm/test_transaction_step_from_account.py +++ b/integration/tests/neon_evm/test_transaction_step_from_account.py @@ -905,19 +905,19 @@ def test_next_operator_can_continue_trx_with_created_spl( treasury_pool, holder_acc, neon_api_client, - erc20_for_spl_proxy_contract, + erc20_for_spl_factory_contract, ): - func_signature = "deploy(string,string,string,uint8)" - func_args = ["Test", "TTT", "http://uri.com", 9] + func_signature = "createErc20ForSplMintable(string,string,uint8,address)" + func_args = ["Test", "TTT", 9, sender_with_tokens.eth_address.hex()] emulate_result = neon_api_client.emulate_contract_call( sender_with_tokens.eth_address.hex(), - erc20_for_spl_proxy_contract.eth_address.hex(), + erc20_for_spl_factory_contract.eth_address.hex(), func_signature, func_args, ) additional_accounts = [Pubkey.from_string(item["pubkey"]) for item in emulate_result["solana_accounts"]] signed_tx = make_contract_call_trx( - evm_loader, sender_with_tokens, erc20_for_spl_proxy_contract, func_signature, func_args + evm_loader, sender_with_tokens, erc20_for_spl_factory_contract, func_signature, func_args ) evm_loader.write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) @@ -925,7 +925,6 @@ def test_next_operator_can_continue_trx_with_created_spl( operator_balance_pubkey = evm_loader.get_operator_balance_pubkey(operator_keypair) second_operator_balance = evm_loader.get_operator_balance_pubkey(second_operator_keypair) - # 1 evm_loader.send_transaction_step_from_account( operator_keypair, operator_balance_pubkey, @@ -942,7 +941,7 @@ def test_next_operator_can_continue_trx_with_created_spl( treasury_pool, holder_acc, additional_accounts, - 5000, + emulate_result["steps_executed"], operator_keypair, ) diff --git a/utils/erc20wrapper.py b/utils/erc20wrapper.py index 89e77fef4d..6f1b6f9833 100644 --- a/utils/erc20wrapper.py +++ b/utils/erc20wrapper.py @@ -15,19 +15,19 @@ class ERC20Wrapper: def __init__( - self, - web3_client: web3client.NeonChainWeb3Client, - faucet, - name, - symbol, - sol_client, - solana_account: Keypair, - decimals=9, - evm_loader_id=None, - account=None, - mintable=True, - contract_address=None, - bank_account=None, + self, + web3_client: web3client.NeonChainWeb3Client, + faucet, + name, + symbol, + sol_client, + solana_account: Keypair, + decimals=9, + evm_loader_id=None, + account=None, + mintable=True, + contract_address=None, + bank_account=None, ): self.solana_associated_token_acc = None self.token_mint = None @@ -41,7 +41,7 @@ def __init__( web3_client.send_neon(bank_account, self.account.address, 50) else: faucet.request_neon(self.account.address, 150) - else: + else: if bank_account is not None: web3_client.send_neon(bank_account, self.account.address, 50) self.name = name @@ -52,95 +52,21 @@ def __init__( self.token_mint: Token self.solana_associated_token_acc: Pubkey - if not contract_address: + if contract_address: + self.contract = web3_client.get_deployed_contract(contract_address, contract_file="EIPs/ERC20/IERC20ForSpl") + else: self.contract_address = self.deploy_wrapper(mintable) + self.contract = self.web3_client.get_deployed_contract(self.contract_address, "EIPs/ERC20/IERC20ForSpl") - if mintable: - self.contract = web3_client.get_deployed_contract( - self.contract_address, - contract_file="external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPLMintable", - solc_version="0.8.24", - ) - else: - self.contract = web3_client.get_deployed_contract( - self.contract_address, - contract_file="external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPL", - solc_version="0.8.24", - ) @property def address(self): """Compatibility with web3.eth.Contract""" return self.contract.address - def _deploy_mintable_wrapper(self): - beacon_erc20_impl, tx = self.web3_client.deploy_and_get_contract( - "external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPLMintable", - "0.8.24", - self.account, - contract_name="ERC20ForSPLMintable", - ) - assert tx["status"] == 1, f"ERC20ForSPLMintable wasn't deployed: {tx}" - - factory_contract, tx = self.web3_client.deploy_and_get_contract( - "external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPLMintableFactory", - "0.8.24", - self.account, - contract_name="ERC20ForSPLMintableFactory", - ) - assert tx["status"] == 1, f"ERC20ForSPLMintableFactory wasn't deployed: {tx}" - - proxy_contract, tx = self.web3_client.deploy_and_get_contract( - "external/neon-contracts/ERC20ForSPL/contracts/openzeppelin-fork/contracts/proxy/ERC1967/ERC1967Proxy", - "0.8.24", - self.account, - contract_name="ERC1967Proxy", - constructor_args=[ - factory_contract.address, - factory_contract.encodeABI("initialize", [beacon_erc20_impl.address]), - ], - ) - assert tx["status"] == 1, f"ERC1967Proxy wasn't deployed: {tx}" - - factory_proxy_contract = self.web3_client.eth.contract(address=proxy_contract.address, abi=factory_contract.abi) - - return factory_proxy_contract - - def _deploy_not_mintable_wrapper(self): - beacon_erc20_impl, tx = self.web3_client.deploy_and_get_contract( - "external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPL", - "0.8.24", - self.account, - contract_name="ERC20ForSPL", - ) - assert tx["status"] == 1, f"ERC20ForSPL wasn't deployed: {tx}" - - factory_contract, tx = self.web3_client.deploy_and_get_contract( - "external/neon-contracts/ERC20ForSPL/contracts/ERC20ForSPLFactory", - "0.8.24", - self.account, - contract_name="ERC20ForSPLFactory", - ) - assert tx["status"] == 1, f"ERC20ForSPL wasn't deployed: {tx}" - - proxy_contract, tx = self.web3_client.deploy_and_get_contract( - "external/neon-contracts/ERC20ForSPL/contracts/openzeppelin-fork/contracts/proxy/ERC1967/ERC1967Proxy", - "0.8.24", - self.account, - contract_name="ERC1967Proxy", - constructor_args=[ - factory_contract.address, - factory_contract.encodeABI("initialize", [beacon_erc20_impl.address]), - ], - ) - assert tx["status"] == 1, f"ERC1967Proxy wasn't deployed: {tx}" - - factory_proxy_contract = self.web3_client.eth.contract(address=proxy_contract.address, abi=factory_contract.abi) - return factory_proxy_contract - def _prepare_spl_token(self): self.token_mint, self.solana_associated_token_acc = self.sol_client.create_spl(self.solana_acc, self.decimals) - metadata = create_metadata_instruction_data(self.name, self.symbol) + metadata = create_metadata_instruction_data(self.name, self.symbol, uri="http://uri.com") txn = Transaction() txn.add( create_metadata_instruction( @@ -156,24 +82,29 @@ def _prepare_spl_token(self): ) def deploy_wrapper(self, mintable: bool): + contract, contract_deploy_tx = self.web3_client.deploy_and_get_contract( + "neon-evm/erc20_for_spl_factory", "0.8.10", self.account, contract_name="ERC20ForSplFactory") + + assert contract_deploy_tx["status"] == 1, f"ERC20 Factory wasn't deployed: {contract_deploy_tx}" + + tx_object = self.web3_client.make_raw_tx(self.account) if mintable: - contract = self._deploy_mintable_wrapper() - tx_object = self.web3_client.make_raw_tx(self.account.address) - instruction_tx = contract.functions.deploy( - self.name, self.symbol, "http://uri.com", self.decimals + instruction_tx = contract.functions.createErc20ForSplMintable( + self.name, self.symbol, self.decimals, self.account.address ).build_transaction(tx_object) else: - contract = self._deploy_not_mintable_wrapper() + self.token_mint, self.solana_associated_token_acc = self.sol_client.create_spl( + self.solana_acc, self.decimals + ) self._prepare_spl_token() - tx_object = self.web3_client.make_raw_tx(self.account.address) - instruction_tx = contract.functions.deploy(bytes(self.token_mint.pubkey)).build_transaction(tx_object) + instruction_tx = contract.functions.createErc20ForSpl(bytes(self.token_mint.pubkey)).build_transaction( + tx_object + ) instruction_receipt = self.web3_client.send_transaction(self.account, instruction_tx) - - assert instruction_receipt["status"] == 1, f"Token wasn't deployed: {instruction_receipt}" if instruction_receipt: - logs = contract.events.TokenDeploy().process_receipt(instruction_receipt) - return logs[0]["args"]["token"] + logs = contract.events.ERC20ForSplCreated().process_receipt(instruction_receipt) + return logs[0]["args"]["pair"] return instruction_receipt # TODO: In all this methods verify if exist self.account @@ -244,12 +175,6 @@ def approve_solana(self, signer, spender, amount, gas_price=None, gas=None) -> T resp = self.web3_client.send_transaction(signer, instruction_tx) return resp - def transfer_ownership(self, signer, new_owner, gas_price=None, gas=None): - tx = self.web3_client.make_raw_tx(signer.address, gas_price=gas_price, gas=gas) - instruction_tx = self.contract.functions.transferOwnership(new_owner).build_transaction(tx) - resp = self.web3_client.send_transaction(signer, instruction_tx) - return resp - def get_balance(self, address): if isinstance(address, LocalAccount): address = address.address