class transacton_cost(unittest.TestCase): @classmethod def setUpClass(self): print( "\n\nhttps://app.zenhub.com/workspaces/solana-evm-6007c75a9dc141001100ccb8/issues/neonlabsorg/proxy-model.py/245" ) self.account = proxy.eth.account.create() print('account.address:', self.account.address) request_airdrop(self.account.address) self.client = Client(solana_url) wallet = WalletAccount(wallet_path()) self.acc = wallet.get_acc() @unittest.skip("only for debug") def test_deploy_cost(self): print("\n\ntest_deploy_cost") compiled = compile_source(CONTRACT) id, interface = compiled.popitem() contract = proxy.eth.contract(abi=interface['abi'], bytecode=interface['bin']) trx = proxy.eth.account.sign_transaction( dict(nonce=proxy.eth.get_transaction_count(self.account.address), chainId=proxy.eth.chain_id, gas=987654321, gasPrice=1000000000, to='', value=0, data=contract.bytecode), self.account.key) print("trx_hash", trx.hash.hex()[2:]) balance_pre = int( self.client.get_balance(self.acc.public_key(), commitment=Confirmed)['result']['value']) print("incoming balance {:,}".format(balance_pre).replace(',', ' ')) signature = proxy.eth.send_raw_transaction(trx.rawTransaction) receipt = proxy.eth.wait_for_transaction_receipt(signature) # self.contract = proxy.eth.contract( # address=receipt.contractAddress, # abi=contract.abi # ) balance_post = int( self.client.get_balance(self.acc.public_key(), commitment=Confirmed)['result']['value']) print("outgoing balance {:,}".format(balance_post).replace(',', ' ')) print("cost {:,}".format(balance_pre - balance_post).replace(',', ' '))
def test_request_air_drop(stubbed_sender: Keypair, stubbed_receiver: Keypair, test_http_client: Client): """Test air drop to stubbed_sender and stubbed_receiver.""" # Airdrop to stubbed_sender resp = test_http_client.request_airdrop(stubbed_sender.public_key, AIRDROP_AMOUNT) assert_valid_response(resp) test_http_client.confirm_transaction(resp["result"]) balance = test_http_client.get_balance(stubbed_sender.public_key) assert balance["result"]["value"] == AIRDROP_AMOUNT # Airdrop to stubbed_receiver resp = test_http_client.request_airdrop(stubbed_receiver, AIRDROP_AMOUNT) assert_valid_response(resp) test_http_client.confirm_transaction(resp["result"]) balance = test_http_client.get_balance(stubbed_receiver) assert balance["result"]["value"] == AIRDROP_AMOUNT
class TestAirdropperIntegration(TestCase): @classmethod def setUpClass(cls) -> None: cls.create_token_mint(cls) cls.deploy_erc20_wrapper_contract(cls) cls.acc_num = 0 def create_token_mint(self): self.solana_client = SolanaClient(SOLANA_URL) with open("proxy/operator-keypairs/id.json") as f: d = json.load(f) self.mint_authority = SolanaAccount(d[0:32]) self.solana_client.request_airdrop(self.mint_authority.public_key(), 1000_000_000_000, Confirmed) while True: balance = self.solana_client.get_balance( self.mint_authority.public_key(), Confirmed)["result"]["value"] if balance > 0: break sleep(1) print('create_token_mint mint, SolanaAccount: ', self.mint_authority.public_key()) self.token = SplToken.create_mint( self.solana_client, self.mint_authority, self.mint_authority.public_key(), 9, TOKEN_PROGRAM_ID, ) def deploy_erc20_wrapper_contract(self): self.wrapper = ERC20Wrapper(proxy, NAME, SYMBOL, self.token, admin, self.mint_authority, EVM_LOADER_ID) self.wrapper.deploy_wrapper() def create_account_instruction(self, eth_address: str, payer: PublicKey): dest_address_solana, nonce = get_evm_loader_account_address( eth_address) neon_token_account = get_associated_token_address( dest_address_solana, ETH_TOKEN_MINT_ID) return TransactionInstruction( program_id=EVM_LOADER_ID, data=create_account_layout(0, 0, bytes.fromhex(eth_address[2:]), nonce), keys=[ AccountMeta(pubkey=payer, is_signer=True, is_writable=True), AccountMeta(pubkey=dest_address_solana, is_signer=False, is_writable=True), AccountMeta(pubkey=neon_token_account, is_signer=False, is_writable=True), AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=ETH_TOKEN_MINT_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=ASSOCIATED_TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), ]) def create_sol_account(self): account = SolanaAccount() print( f"New solana account created: {account.public_key().to_base58()}. Airdropping..." ) self.solana_client.request_airdrop(account.public_key(), 1000_000_000_000, Confirmed) return account def create_token_account(self, owner: PublicKey, mint_amount: int): new_token_account = self.wrapper.create_associated_token_account( owner, self.mint_authority) self.wrapper.mint_to(new_token_account, mint_amount) return new_token_account def create_eth_account(self): self.acc_num += 1 account = proxy.eth.account.create( f'neonlabsorg/proxy-model.py/issues/344/eth_account{self.acc_num}') print(f"NEON account created: {account.address}") return account def test_success_airdrop_simple_case(self): from_owner = self.create_sol_account() mint_amount = 1000_000_000_000 from_spl_token_acc = self.create_token_account(from_owner.public_key(), mint_amount) to_neon_acc = self.create_eth_account().address self.assertEqual(self.wrapper.get_balance(from_spl_token_acc), mint_amount) self.assertEqual(self.wrapper.get_balance(to_neon_acc), 0) TRANSFER_AMOUNT = 123456 trx = Transaction() trx.add( self.create_account_instruction(to_neon_acc, from_owner.public_key())) trx.add( self.wrapper.create_neon_erc20_account_instruction( from_owner.public_key(), to_neon_acc)) trx.add( self.wrapper.create_input_liquidity_instruction( from_owner.public_key(), from_spl_token_acc, to_neon_acc, TRANSFER_AMOUNT)) opts = TxOpts(skip_preflight=True, skip_confirmation=False) print(self.solana_client.send_transaction(trx, from_owner, opts=opts)) self.assertEqual(self.wrapper.get_balance(from_spl_token_acc), mint_amount - TRANSFER_AMOUNT) self.assertEqual(self.wrapper.get_balance(to_neon_acc), TRANSFER_AMOUNT) wait_time = 0 eth_balance = 0 while wait_time < MAX_AIRDROP_WAIT_TIME: eth_balance = proxy.eth.get_balance(to_neon_acc) balance_ready = eth_balance > 0 and eth_balance < 10 * pow(10, 18) if balance_ready: break sleep(1) wait_time += 1 print(f"Wait time for simple transaction (1 airdrop): {wait_time}") eth_balance = proxy.eth.get_balance(to_neon_acc) print("NEON balance is: ", eth_balance) self.assertTrue( eth_balance > 0 and eth_balance < 10 * pow(10, 18)) # 10 NEON is a max airdrop amount def test_success_airdrop_complex_case(self): from_owner = self.create_sol_account() mint_amount = 1000_000_000_000 from_spl_token_acc = self.create_token_account(from_owner.public_key(), mint_amount) to_neon_acc1 = self.create_eth_account().address to_neon_acc2 = self.create_eth_account().address self.assertEqual(self.wrapper.get_balance(from_spl_token_acc), mint_amount) self.assertEqual(self.wrapper.get_balance(to_neon_acc1), 0) self.assertEqual(self.wrapper.get_balance(to_neon_acc2), 0) TRANSFER_AMOUNT1 = 123456 TRANSFER_AMOUNT2 = 654321 trx = Transaction() trx.add( self.create_account_instruction(to_neon_acc1, from_owner.public_key())) trx.add( self.create_account_instruction(to_neon_acc2, from_owner.public_key())) trx.add( self.wrapper.create_neon_erc20_account_instruction( from_owner.public_key(), to_neon_acc1)) trx.add( self.wrapper.create_neon_erc20_account_instruction( from_owner.public_key(), to_neon_acc2)) trx.add( self.wrapper.create_input_liquidity_instruction( from_owner.public_key(), from_spl_token_acc, to_neon_acc1, TRANSFER_AMOUNT1)) trx.add( self.wrapper.create_input_liquidity_instruction( from_owner.public_key(), from_spl_token_acc, to_neon_acc2, TRANSFER_AMOUNT2)) opts = TxOpts(skip_preflight=True, skip_confirmation=False) print(self.solana_client.send_transaction(trx, from_owner, opts=opts)) self.assertEqual(self.wrapper.get_balance(from_spl_token_acc), mint_amount - TRANSFER_AMOUNT1 - TRANSFER_AMOUNT2) self.assertEqual(self.wrapper.get_balance(to_neon_acc1), TRANSFER_AMOUNT1) self.assertEqual(self.wrapper.get_balance(to_neon_acc2), TRANSFER_AMOUNT2) wait_time = 0 eth_balance1 = 0 eth_balance2 = 0 while wait_time < MAX_AIRDROP_WAIT_TIME: eth_balance1 = proxy.eth.get_balance(to_neon_acc1) eth_balance2 = proxy.eth.get_balance(to_neon_acc2) balance1_ready = eth_balance1 > 0 and eth_balance1 < 10 * pow( 10, 18) balance2_ready = eth_balance2 > 0 and eth_balance2 < 10 * pow( 10, 18) if balance1_ready and balance2_ready: break sleep(1) wait_time += 1 print(f"Wait time for complex transaction (2 airdrops): {wait_time}") eth_balance1 = proxy.eth.get_balance(to_neon_acc1) eth_balance2 = proxy.eth.get_balance(to_neon_acc2) print("NEON balance 1 is: ", eth_balance1) print("NEON balance 2 is: ", eth_balance2) self.assertTrue( eth_balance1 > 0 and eth_balance1 < 10 * pow(10, 18)) # 10 NEON is a max airdrop amount self.assertTrue( eth_balance2 > 0 and eth_balance2 < 10 * pow(10, 18)) # 10 NEON is a max airdrop amount def test_no_airdrop(self): from_owner = self.create_sol_account() mint_amount = 1000_000_000_000 from_spl_token_acc = self.create_token_account(from_owner.public_key(), mint_amount) to_neon_acc = self.create_eth_account().address sleep(15) self.assertEqual(self.wrapper.get_balance(from_spl_token_acc), mint_amount) self.assertEqual(self.wrapper.get_balance(to_neon_acc), 0) trx = Transaction() trx.add( self.create_account_instruction(to_neon_acc, from_owner.public_key())) trx.add( self.wrapper.create_neon_erc20_account_instruction( from_owner.public_key(), to_neon_acc)) # No input liquidity opts = TxOpts(skip_preflight=True, skip_confirmation=False) print(self.solana_client.send_transaction(trx, from_owner, opts=opts)) sleep(15) eth_balance = proxy.eth.get_balance(to_neon_acc) print("NEON balance is: ", eth_balance) self.assertEqual(eth_balance, 0)
class Test_read_only_accounts(unittest.TestCase): @classmethod def setUpClass(cls): cls.create_token_mint(cls) cls.deploy_erc20_wrapper_contract(cls) cls.deploy_test_contract(cls) def account_exists(self, key: PublicKey) -> Boolean: info = self.solana_client.get_account_info(key) info["result"]["value"] is not None def create_token_mint(self): self.solana_client = SolanaClient(solana_url) with open("proxy/operator-keypairs/id.json") as f: d = json.load(f) self.solana_account = SolanaAccount(d[0:32]) self.solana_client.request_airdrop(self.solana_account.public_key(), 1000_000_000_000, Confirmed) while True: balance = self.solana_client.get_balance( self.solana_account.public_key(), Confirmed)["result"]["value"] if balance > 0: break sleep(1) print('create_token_mint mint, SolanaAccount: ', self.solana_account.public_key()) self.token = SplToken.create_mint( self.solana_client, self.solana_account, self.solana_account.public_key(), 9, TOKEN_PROGRAM_ID, ) def deploy_erc20_wrapper_contract(self): self.wrapper = ERC20Wrapper(proxy, "NEON", "NEON", self.token, admin, self.solana_account, PublicKey(EVM_LOADER_ID)) self.wrapper.deploy_wrapper() def deploy_test_contract(self): compiled = compile_source(CONTRACT) id, interface = compiled.popitem() contract = proxy.eth.contract(abi=interface['abi'], bytecode=interface['bin']) trx = proxy.eth.account.sign_transaction( dict(nonce=proxy.eth.get_transaction_count(admin.address), chainId=proxy.eth.chain_id, gas=987654321, gasPrice=1000000000, to='', value=0, data=contract.bytecode), admin.key) signature = proxy.eth.send_raw_transaction(trx.rawTransaction) receipt = proxy.eth.wait_for_transaction_receipt(signature) self.contract = proxy.eth.contract(address=receipt.contractAddress, abi=contract.abi) def test_balanceOf(self): account = proxy.eth.account.create() solana_account = self.wrapper.get_neon_account_address(account.address) self.assertFalse(self.account_exists(solana_account)) nonce = proxy.eth.get_transaction_count(admin.address) tx = self.contract.functions.balanceOf( account.address).buildTransaction({"nonce": nonce}) tx = proxy.eth.account.sign_transaction(tx, admin.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertIsNotNone(tx_receipt) self.assertEqual(tx_receipt.status, 1) self.assertFalse(self.account_exists(solana_account)) def test_erc20_balanceOf(self): erc20 = self.wrapper.erc20_interface() account = proxy.eth.account.create() solana_account = self.wrapper.get_neon_account_address(account.address) self.assertFalse(self.account_exists(solana_account)) token_account = self.wrapper.get_neon_erc20_account_address( account.address) self.assertFalse(self.account_exists(token_account)) nonce = proxy.eth.get_transaction_count(admin.address) tx = erc20.functions.balanceOf(account.address).buildTransaction( {"nonce": nonce}) tx = proxy.eth.account.sign_transaction(tx, admin.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertIsNotNone(tx_receipt) self.assertEqual(tx_receipt.status, 1) self.assertFalse(self.account_exists(solana_account)) self.assertFalse(self.account_exists(token_account))
class Test_erc20_wrapper_contract(unittest.TestCase): @classmethod def setUpClass(cls): print("\n\nhttps://github.com/neonlabsorg/proxy-model.py/issues/197") print('admin.key:', admin.key.hex()) print('admin.address:', admin.address) print('user.key:', user.key.hex()) print('user.address:', user.address) cls.create_token_mint(cls) cls.deploy_erc20_wrapper_contract(cls) cls.create_token_accounts(cls) def create_token_mint(self): self.solana_client = SolanaClient(solana_url) with open("proxy/operator-keypairs/id.json") as f: d = json.load(f) self.solana_account = SolanaAccount(d[0:32]) self.solana_client.request_airdrop(self.solana_account.public_key(), 1000_000_000_000, Confirmed) while True: balance = self.solana_client.get_balance( self.solana_account.public_key(), Confirmed)["result"]["value"] if balance > 0: break sleep(1) print('create_token_mint mint, SolanaAccount: ', self.solana_account.public_key()) self.token = SplToken.create_mint( self.solana_client, self.solana_account, self.solana_account.public_key(), 9, TOKEN_PROGRAM_ID, ) def deploy_erc20_wrapper_contract(self): self.wrapper = ERC20Wrapper(proxy, NAME, SYMBOL, self.token, admin, self.solana_account, PublicKey(EVM_LOADER_ID)) self.wrapper.deploy_wrapper() def create_token_accounts(self): admin_token_key = self.wrapper.get_neon_erc20_account_address( admin.address) admin_token_info = { "key": admin_token_key, "owner": self.wrapper.get_neon_account_address(admin.address), "contract": self.wrapper.solana_contract_address, "mint": self.token.pubkey } instr = NeonInstruction( self.solana_account.public_key()).createERC20TokenAccountTrx( admin_token_info) self.solana_client.send_transaction(instr, self.solana_account, opts=TxOpts( skip_preflight=True, skip_confirmation=False)) self.wrapper.mint_to(admin_token_key, 10_000_000_000_000) def test_erc20_name(self): erc20 = proxy.eth.contract(address=self.wrapper.neon_contract_address, abi=self.wrapper.wrapper['abi']) name = erc20.functions.name().call() self.assertEqual(name, NAME) def test_erc20_symbol(self): erc20 = proxy.eth.contract(address=self.wrapper.neon_contract_address, abi=self.wrapper.wrapper['abi']) sym = erc20.functions.symbol().call() self.assertEqual(sym, SYMBOL) def test_erc20_decimals(self): erc20 = self.wrapper.erc20_interface() decs = erc20.functions.decimals().call() self.assertEqual(decs, 9) def test_erc20_totalSupply(self): erc20 = self.wrapper.erc20_interface() ts = erc20.functions.totalSupply().call() self.assertGreater(ts, 0) def test_erc20_balanceOf(self): erc20 = self.wrapper.erc20_interface() b = erc20.functions.balanceOf(admin.address).call() self.assertGreater(b, 0) b = erc20.functions.balanceOf(user.address).call() self.assertEqual(b, 0) def test_erc20_transfer(self): transfer_value = 1000 erc20 = self.wrapper.erc20_interface() admin_balance_before = erc20.functions.balanceOf(admin.address).call() user_balance_before = erc20.functions.balanceOf(user.address).call() nonce = proxy.eth.get_transaction_count(proxy.eth.default_account) tx = {'nonce': nonce} tx = erc20.functions.transfer(user.address, transfer_value).buildTransaction(tx) tx = proxy.eth.account.sign_transaction(tx, admin.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertIsNotNone(tx_receipt) self.assertEqual(tx_receipt.status, 1) admin_balance_after = erc20.functions.balanceOf(admin.address).call() user_balance_after = erc20.functions.balanceOf(user.address).call() self.assertEqual(admin_balance_after, admin_balance_before - transfer_value) self.assertEqual(user_balance_after, user_balance_before + transfer_value) def test_erc20_transfer_not_enough_funds(self): transfer_value = 100_000_000_000_000 erc20 = self.wrapper.erc20_interface() admin_balance_before = erc20.functions.balanceOf(admin.address).call() user_balance_before = erc20.functions.balanceOf(user.address).call() with self.assertRaisesRegex(Exception, "ERC20 transfer failed"): erc20.functions.transfer(user.address, transfer_value).buildTransaction() admin_balance_after = erc20.functions.balanceOf(admin.address).call() user_balance_after = erc20.functions.balanceOf(user.address).call() self.assertEqual(admin_balance_after, admin_balance_before) self.assertEqual(user_balance_after, user_balance_before) def test_erc20_transfer_out_of_bounds(self): transfer_value = 0xFFFF_FFFF_FFFF_FFFF + 1 erc20 = self.wrapper.erc20_interface() with self.assertRaisesRegex(Exception, "ERC20 transfer failed"): erc20.functions.transfer(user.address, transfer_value).buildTransaction() def test_erc20_approve(self): approve_value = 1000 erc20 = self.wrapper.erc20_interface() allowance_before = erc20.functions.allowance(admin.address, user.address).call() nonce = proxy.eth.get_transaction_count(admin.address) tx = erc20.functions.approve( user.address, approve_value).buildTransaction({'nonce': nonce}) tx = proxy.eth.account.sign_transaction(tx, admin.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertEqual(tx_receipt.status, 1) self.assertIsNotNone(tx_receipt) allowance_after = erc20.functions.allowance(admin.address, user.address).call() self.assertEqual(allowance_after, allowance_before + approve_value) def test_erc20_transferFrom(self): approve_value = 1000 transfer_value = 100 erc20 = self.wrapper.erc20_interface() nonce = proxy.eth.get_transaction_count(admin.address) tx = erc20.functions.approve( user.address, approve_value).buildTransaction({'nonce': nonce}) tx = proxy.eth.account.sign_transaction(tx, admin.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertIsNotNone(tx_receipt) self.assertEqual(tx_receipt.status, 1) allowance_before = erc20.functions.allowance(admin.address, user.address).call() admin_balance_before = erc20.functions.balanceOf(admin.address).call() user_balance_before = erc20.functions.balanceOf(user.address).call() nonce = proxy.eth.get_transaction_count(user.address) tx = erc20.functions.transferFrom(admin.address, user.address, transfer_value).buildTransaction({ 'nonce': nonce, 'from': user.address }) tx = proxy.eth.account.sign_transaction(tx, user.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertIsNotNone(tx_receipt) self.assertEqual(tx_receipt.status, 1) allowance_after = erc20.functions.allowance(admin.address, user.address).call() admin_balance_after = erc20.functions.balanceOf(admin.address).call() user_balance_after = erc20.functions.balanceOf(user.address).call() self.assertEqual(allowance_after, allowance_before - transfer_value) self.assertEqual(admin_balance_after, admin_balance_before - transfer_value) self.assertEqual(user_balance_after, user_balance_before + transfer_value) def test_erc20_transferFrom_beyond_approve(self): transfer_value = 10_000_000 erc20 = self.wrapper.erc20_interface() with self.assertRaisesRegex(Exception, "ERC20 transferFrom failed"): erc20.functions.transferFrom(admin.address, user.address, transfer_value).buildTransaction( {'from': user.address}) def test_erc20_transferFrom_out_of_bounds(self): transfer_value = 0xFFFF_FFFF_FFFF_FFFF + 1 erc20 = self.wrapper.erc20_interface() with self.assertRaisesRegex(Exception, "ERC20 transferFrom failed"): erc20.functions.transferFrom(admin.address, user.address, transfer_value).buildTransaction( {'from': user.address}) def test_erc20_approveSolana(self): delegate = SolanaAccount() approve_value = 1000 erc20 = self.wrapper.erc20_interface() nonce = proxy.eth.get_transaction_count(admin.address) tx = erc20.functions.approveSolana(bytes(delegate.public_key()), approve_value).buildTransaction( {'nonce': nonce}) tx = proxy.eth.account.sign_transaction(tx, admin.key) tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash) self.assertEqual(tx_receipt.status, 1) self.assertIsNotNone(tx_receipt) accounts = self.solana_client.get_token_accounts_by_delegate( delegate.public_key(), TokenAccountOpts(mint=self.token.pubkey), commitment=Recent) accounts = list( map(lambda a: PublicKey(a['pubkey']), accounts['result']['value'])) self.assertIn( self.wrapper.get_neon_erc20_account_address(admin.address), accounts)