def create_mint( cls, conn: Client, payer: Account, mint_authority: PublicKey, decimals: int, program_id: PublicKey, freeze_authority: Optional[PublicKey] = None, skip_confirmation: bool = False, ) -> Token: """Create and initialize a token. :param conn: RPC connection to a solana cluster. :param payer: Fee payer for transaction. :param mint_authority: Account or multisig that will control minting. :param decimals: Location of the decimal place. :param program_id: SPL Token program account. :param freeze_authority: (optional) Account or multisig that can freeze token accounts. :param skip_confirmation: (optional) Option to skip transaction confirmation. :return: Token object for the newly minted token. If skip confirmation is set to `False`, this method will block for at most 30 seconds or until the transaction is confirmed. """ # Allocate memory for the account balance_needed = Token.get_min_balance_rent_for_exempt_for_mint(conn) # Construct transaction token, txn, payer, mint_account, opts = _TokenCore._create_mint_args( conn, payer, mint_authority, decimals, program_id, freeze_authority, skip_confirmation, balance_needed, cls) # Send the two instructions conn.send_transaction(txn, payer, mint_account, opts=opts) return cast(Token, token)
def create_wrapped_native_account( conn: Client, program_id: PublicKey, owner: PublicKey, payer: Account, amount: int, skip_confirmation: bool = False, ) -> PublicKey: """Create and initialize a new account on the special native token mint. :param conn: RPC connection to a solana cluster. :param program_id: SPL Token program account. :param owner: The owner of the new token account. :param payer: The source of the lamports to initialize, and payer of the initialization fees. :param amount: The amount of lamports to wrap. :param skip_confirmation: (optional) Option to skip transaction confirmation. :return: The new token account. If skip confirmation is set to `False`, this method will block for at most 30 seconds or until the transaction is confirmed. """ # Allocate memory for the account balance_needed = Token.get_min_balance_rent_for_exempt_for_account( conn) new_account_public_key, txn, payer, new_account, opts = _TokenCore._create_wrapped_native_account_args( program_id, owner, payer, amount, skip_confirmation, balance_needed) conn.send_transaction(txn, payer, new_account, opts=opts) return new_account_public_key
def create_mint( conn: Client, payer: Account, mint_authority: PublicKey, decimals: int, program_id: PublicKey, freeze_authority: Optional[PublicKey] = None, skip_confirmation: bool = False, ) -> Token: """Create and initialize a token. :param conn: RPC connection to a solana cluster. :param payer: Fee payer for transaction. :param mint_authority: Account or multisig that will control minting. :param decimals: Location of the decimal place. :param program_id: SPL Token program account. :param freeze_authority: (optional) Account or multisig that can freeze token accounts. :param skip_confirmation: (optional) Option to skip transaction confirmation. :return: Token object for the newly minted token. If skip confirmation is set to `False`, this method will block for at most 30 seconds or until the transaction is confirmed. """ mint_account = Account() token = Token(conn, mint_account.public_key(), program_id, payer) # Allocate memory for the account balance_needed = Token.get_min_balance_rent_for_exempt_for_mint(conn) # Construct transaction txn = Transaction() txn.add( sp.create_account( sp.CreateAccountParams( from_pubkey=payer.public_key(), new_account_pubkey=mint_account.public_key(), lamports=balance_needed, space=MINT_LAYOUT.sizeof(), program_id=program_id, ) ) ) txn.add( spl_token.initialize_mint( spl_token.InitializeMintParams( program_id=program_id, mint=mint_account.public_key(), decimals=decimals, mint_authority=mint_authority, freeze_authority=freeze_authority, ) ) ) # Send the two instructions conn.send_transaction( txn, payer, mint_account, opts=TxOpts(skip_confirmation=skip_confirmation, skip_preflight=True) ) return token
def topup(self, api_endpoint, to, amount=None, skip_confirmation=True): """ Send a small amount of native currency to the specified wallet to handle gas fees. Return a status flag of success or fail and the native transaction data. """ msg = "" try: # Connect to the api_endpoint client = Client(api_endpoint) msg += "Initialized client" # List accounts sender_account = Account(self.private_key) dest_account = PublicKey(to) msg += " | Gathered accounts" # List signers signers = [sender_account] # Start transaction tx = Transaction() # Determine the amount to send try: if amount is None: min_rent_reseponse = client.get_minimum_balance_for_rent_exemption( ACCOUNT_LAYOUT.sizeof()) lamports = min_rent_reseponse["result"] else: lamports = int(amount) msg += f" | Fetched lamports: {lamports * 1e-9} SOL" except Exception as e: msg += " | ERROR: couldn't process lamports" raise (e) # Generate transaction transfer_ix = transfer( TransferParams(from_pubkey=sender_account.public_key(), to_pubkey=dest_account, lamports=lamports)) tx = tx.add(transfer_ix) msg += f" | Transferring funds" # Send request try: response = client.send_transaction( tx, *signers, opts=types.TxOpts(skip_confirmation=skip_confirmation)) return json.dumps({ 'status': HTTPStatus.OK, 'msg': f"Successfully sent {lamports * 1e-9} SOL to {to}", 'tx': response.get('result') if skip_confirmation else response['result']['transaction']['signatures'], }) except Exception as e: msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}" raise (e) except Exception as e: return json.dumps({ 'status': HTTPStatus.BAD_REQUEST, 'msg': msg, })
def mint_to(self, api_endpoint, pool_account, dest, amount, skip_confirmation=True): msg = "" client = Client(api_endpoint) msg += "Initialized client" # Create account objects source_account = Account(self.private_key) signers = [source_account] pool = self.load_binary_option(api_endpoint, pool_account) # List non-derived accounts pool_account = PublicKey(pool_account) dest_account = PublicKey(dest) escrow_mint_account = PublicKey(pool["escrow_mint"]) mint_authority_account = source_account.public_key() payer_account = source_account.public_key() token_account = PublicKey(TOKEN_PROGRAM_ID) tx = Transaction() token_pda_address = get_associated_token_address( dest_account, escrow_mint_account) associated_token_account_ix = create_associated_token_account( payer=payer_account, owner=dest_account, mint=escrow_mint_account, ) tx = tx.add(associated_token_account_ix) mint_to_ix = mint_to( MintToParams( program_id=token_account, mint=escrow_mint_account, dest=token_pda_address, mint_authority=mint_authority_account, amount=int(amount), signers=[mint_authority_account], )) tx = tx.add(mint_to_ix) # Send request try: response = client.send_transaction( tx, *signers, opts=types.TxOpts(skip_confirmation=skip_confirmation)) return json.dumps({ 'status': HTTPStatus.OK, 'msg': msg + f" | MintTo {dest} successful", 'tx': response.get('result') if skip_confirmation else response['result']['transaction']['signatures'], }) except Exception as e: msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}" raise (e)
def settle(self, api_endpoint, pool_account, winning_mint, skip_confirmation=True): msg = "" client = Client(api_endpoint) msg += "Initialized client" # Create account objects source_account = Account(self.private_key) # Signers signers = [source_account] # List non-derived accounts pool_account = PublicKey(pool_account) winning_mint_account = PublicKey(winning_mint) tx = Transaction() settle_ix = settle_instruction( pool_account, winning_mint_account, source_account.public_key(), ) tx = tx.add(settle_ix) # Send request try: response = client.send_transaction( tx, *signers, opts=types.TxOpts(skip_confirmation=skip_confirmation)) return json.dumps({ 'status': HTTPStatus.OK, 'msg': msg + f" | Settle successful, winner: {str(winning_mint_account)}", 'tx': response.get('result') if skip_confirmation else response['result']['transaction']['signatures'], }) except Exception as e: msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}" raise (e)
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)
def collect(self, api_endpoint, pool_account, collector, skip_confirmation=True): msg = "" client = Client(api_endpoint) msg += "Initialized client" signers = [Account(self.private_key)] pool = self.load_binary_option(api_endpoint, pool_account) pool_account = PublicKey(pool_account) collector_account = PublicKey(collector) escrow_account = PublicKey(pool["escrow"]) escrow_mint_account = PublicKey(pool["escrow_mint"]) long_token_mint_account = PublicKey(pool["long_mint"]) short_token_mint_account = PublicKey(pool["short_mint"]) token_account = PublicKey(TOKEN_PROGRAM_ID) escrow_authority_account = PublicKey.find_program_address( [ bytes(long_token_mint_account), bytes(short_token_mint_account), bytes(token_account), bytes(PublicKey(BINARY_OPTION_PROGRAM_ID)) ], PublicKey(BINARY_OPTION_PROGRAM_ID), )[0] # Transaction tx = Transaction() atas = [] for mint_account in (long_token_mint_account, short_token_mint_account, escrow_mint_account): token_pda_address = get_associated_token_address( collector_account, mint_account) associated_token_account_info = client.get_account_info( token_pda_address) account_info = associated_token_account_info['result']['value'] if account_info is not None: account_state = ACCOUNT_LAYOUT.parse( base64.b64decode(account_info['data'][0])).state else: account_state = 0 if account_state == 0: msg += f" | Error Fetching PDA: {token_pda_address}" raise Exception() else: msg += f" | Fetched PDA: {token_pda_address}" atas.append(token_pda_address) collect_ix = collect_instruction( pool_account, collector_account, atas[0], atas[1], atas[2], long_token_mint_account, short_token_mint_account, escrow_account, escrow_authority_account, token_account, ) tx = tx.add(collect_ix) try: response = client.send_transaction( tx, *signers, opts=types.TxOpts(skip_confirmation=skip_confirmation)) return json.dumps({ 'status': HTTPStatus.OK, 'msg': msg + f" | Collect successful", 'tx': response.get('result') if skip_confirmation else response['result']['transaction']['signatures'], }) except Exception as e: msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}" print(msg) raise (e)
def trade(self, api_endpoint, pool_account, buyer_encrypted_private_key, seller_encrypted_private_key, size, buyer_price, seller_price, skip_confirmation=True): msg = "" client = Client(api_endpoint) msg += "Initialized client" # Create account objects buyer_private_key = list( self.cipher.decrypt(buyer_encrypted_private_key)) seller_private_key = list( self.cipher.decrypt(seller_encrypted_private_key)) assert (len(buyer_private_key) == 32) assert (len(seller_private_key) == 32) source_account = Account(self.private_key) buyer = Account(buyer_private_key) seller = Account(seller_private_key) # Signers signers = [buyer, seller, source_account] pool = self.load_binary_option(api_endpoint, pool_account) # List non-derived accounts pool_account = PublicKey(pool_account) escrow_account = PublicKey(pool["escrow"]) escrow_mint_account = PublicKey(pool["escrow_mint"]) long_token_mint_account = PublicKey(pool["long_mint"]) short_token_mint_account = PublicKey(pool["short_mint"]) buyer_account = buyer.public_key() seller_account = seller.public_key() token_account = PublicKey(TOKEN_PROGRAM_ID) escrow_owner_account = PublicKey.find_program_address( [ bytes(long_token_mint_account), bytes(short_token_mint_account), bytes(token_account), bytes(PublicKey(BINARY_OPTION_PROGRAM_ID)) ], PublicKey(BINARY_OPTION_PROGRAM_ID), )[0] # Transaction tx = Transaction() atas = [] for acct in [buyer_account, seller_account]: acct_atas = [] for mint_account in (long_token_mint_account, short_token_mint_account, escrow_mint_account): token_pda_address = get_associated_token_address( acct, mint_account) associated_token_account_info = client.get_account_info( token_pda_address) account_info = associated_token_account_info['result']['value'] if account_info is not None: account_state = ACCOUNT_LAYOUT.parse( base64.b64decode(account_info['data'][0])).state else: account_state = 0 if account_state == 0: msg += f" | Creating PDA: {token_pda_address}" associated_token_account_ix = create_associated_token_account( payer=source_account.public_key(), owner=acct, mint=mint_account, ) tx = tx.add(associated_token_account_ix) else: msg += f" | Fetched PDA: {token_pda_address}" acct_atas.append(token_pda_address) atas.append(acct_atas) trade_ix = trade_instruction( pool_account, escrow_account, long_token_mint_account, short_token_mint_account, buyer_account, seller_account, atas[0][2], atas[1][2], atas[0][0], atas[0][1], atas[1][0], atas[1][1], escrow_owner_account, token_account, int(size), int(buyer_price), int(seller_price), ) tx = tx.add(trade_ix) # Send request try: response = client.send_transaction( tx, *signers, opts=types.TxOpts(skip_confirmation=skip_confirmation)) return json.dumps({ 'status': HTTPStatus.OK, 'msg': msg + f" | Trade successful", 'tx': response.get('result') if skip_confirmation else response['result']['transaction']['signatures'], }) except Exception as e: msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}" raise (e)
def initialize(self, api_endpoint, escrow_mint, decimals=2, skip_confirmation=True): msg = "" # Initialize Clinet client = Client(api_endpoint) msg += "Initialized client" # Create account objects source_account = Account(self.private_key) pool = Account() long_escrow = Account() short_escrow = Account() long_mint = Account() short_mint = Account() # List non-derived accounts pool_account = pool.public_key() escrow_mint_account = PublicKey(escrow_mint) escrow_account = long_escrow.public_key() long_token_mint_account = long_mint.public_key() short_token_mint_account = short_mint.public_key() mint_authority_account = source_account.public_key() update_authority_account = source_account.public_key() token_account = PublicKey(TOKEN_PROGRAM_ID) system_account = PublicKey(SYSTEM_PROGRAM_ID) rent_account = PublicKey(SYSVAR_RENT_ID) msg += " | Gathered accounts" # List signers signers = [ source_account, long_mint, short_mint, long_escrow, short_escrow, pool ] # Start transaction tx = Transaction() # Create Token Metadata init_binary_option_ix = initialize_binary_option_instruction( pool_account, escrow_mint_account, escrow_account, long_token_mint_account, short_token_mint_account, mint_authority_account, update_authority_account, token_account, system_account, rent_account, decimals, ) tx = tx.add(init_binary_option_ix) msg += f" | Creating binary option" # Send request try: response = client.send_transaction( tx, *signers, opts=types.TxOpts(skip_confirmation=skip_confirmation)) return json.dumps({ 'status': HTTPStatus.OK, 'binary_option': str(pool_account), 'msg': msg + f" | Successfully created binary option {str(pool_account)}", 'tx': response.get('result') if skip_confirmation else response['result']['transaction']['signatures'], }) except Exception as e: msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}" raise (e)
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)