async def test_token(alt_stubbed_sender, test_http_client_async) -> AsyncToken: """Test create mint.""" resp = await test_http_client_async.request_airdrop(alt_stubbed_sender.public_key(), AIRDROP_AMOUNT) confirmed = await aconfirm_transaction(test_http_client_async, resp["result"]) assert_valid_response(confirmed) expected_decimals = 6 expected_freeze_authority = Account() token_client = await AsyncToken.create_mint( test_http_client_async, alt_stubbed_sender, alt_stubbed_sender.public_key(), expected_decimals, TOKEN_PROGRAM_ID, expected_freeze_authority.public_key(), ) assert token_client.pubkey assert token_client.program_id == TOKEN_PROGRAM_ID assert token_client.payer.public_key() == alt_stubbed_sender.public_key() resp = await test_http_client_async.get_account_info(token_client.pubkey) assert_valid_response(resp) assert resp["result"]["value"]["owner"] == str(TOKEN_PROGRAM_ID) mint_data = layouts.MINT_LAYOUT.parse(decode_byte_string(resp["result"]["value"]["data"][0])) assert mint_data.is_initialized assert mint_data.decimals == expected_decimals assert mint_data.supply == 0 assert PublicKey(mint_data.mint_authority) == alt_stubbed_sender.public_key() assert PublicKey(mint_data.freeze_authority) == expected_freeze_authority.public_key() return token_client
def _create_account_args( self, owner: PublicKey, skip_confirmation: bool, balance_needed: int, ) -> Tuple[PublicKey, Transaction, Account, Account, TxOpts]: new_account = Account() # Allocate memory for the account # Construct transaction txn = Transaction() txn.add( sp.create_account( sp.CreateAccountParams( from_pubkey=self.payer.public_key(), new_account_pubkey=new_account.public_key(), lamports=balance_needed, space=ACCOUNT_LAYOUT.sizeof(), program_id=self.program_id, ))) txn.add( spl_token.initialize_account( spl_token.InitializeAccountParams( account=new_account.public_key(), mint=self.pubkey, owner=owner, program_id=self.program_id))) return ( new_account.public_key(), txn, self.payer, new_account, TxOpts(skip_preflight=True, skip_confirmation=skip_confirmation), )
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)
def test_account_keypair(): """Validate account keypair against account's private and public key.""" expected_account = Account() keypair = expected_account.keypair() decoded_keypair = b58decode(keypair) actual_account = Account(decoded_keypair[:32]) assert expected_account.public_key() == actual_account.public_key() assert expected_account.secret_key() == actual_account.secret_key()
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 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 test_dedup_signatures(stubbed_blockhash): """Test signature deduplication.""" acc1, acc2 = Account(), Account() transfer1 = sp.transfer( sp.TransferParams(from_pubkey=acc1.public_key(), to_pubkey=acc2.public_key(), lamports=123)) transfer2 = sp.transfer( sp.TransferParams(from_pubkey=acc1.public_key(), to_pubkey=acc2.public_key(), lamports=123)) txn = txlib.Transaction(recent_blockhash=stubbed_blockhash).add( transfer1, transfer2) txn.sign(acc1)
def cancel_order(self, owner: Account, order: t.Order, opts: TxOpts = TxOpts()) -> RPCResponse: txn = Transaction().add( self.make_cancel_order_instruction(owner.public_key(), order)) return self._conn.send_transaction(txn, owner, opts=opts)
def make_place_order_instruction( # pylint: disable=too-many-arguments self, payer: PublicKey, owner: Account, order_type: OrderType, side: Side, limit_price: int, max_quantity: int, client_id: int, open_order_account: PublicKey, ) -> TransactionInstruction: if self.state.base_size_number_to_lots(max_quantity) < 0: raise Exception("Size lot %d is too small" % max_quantity) if self.state.price_number_to_lots(limit_price) < 0: raise Exception("Price lot %d is too small" % limit_price) return instructions.new_order( instructions.NewOrderParams( market=self.state.public_key(), open_orders=open_order_account, payer=payer, owner=owner.public_key(), request_queue=self.state.request_queue(), base_vault=self.state.base_vault(), quote_vault=self.state.quote_vault(), side=side, limit_price=limit_price, max_quantity=max_quantity, order_type=order_type, client_id=client_id, program_id=self.state.program_id(), ))
class Wallet: def __init__(self, secret_key): self.logger: logging.Logger = logging.getLogger( self.__class__.__name__) self.secret_key = secret_key[0:32] self.account = Account(self.secret_key) @property def address(self) -> PublicKey: return self.account.public_key() def save(self, filename: str, overwrite: bool = False) -> None: if os.path.isfile(filename) and not overwrite: raise Exception(f"Wallet file '{filename}' already exists.") with open(filename, "w") as json_file: json.dump(list(self.secret_key), json_file) @staticmethod def load(filename: str = _DEFAULT_WALLET_FILENAME) -> "Wallet": if not os.path.isfile(filename): logging.error(f"Wallet file '{filename}' is not present.") raise Exception(f"Wallet file '{filename}' is not present.") else: with open(filename) as json_file: data = json.load(json_file) return Wallet(data) @staticmethod def create() -> "Wallet": new_account = Account() new_secret_key = new_account.secret_key() return Wallet(new_secret_key)
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 create_account( self, owner: PublicKey, skip_confirmation: bool = False, ) -> PublicKey: """Create and initialize a new account. This account may then be used as a `transfer()` or `approve()` destination. :param owner: User account that will own the new account. :param skip_confirmation: (optional) Option to skip transaction confirmation. :return: Public key of the new empty account. If skip confirmation is set to `False`, this method will block for at most 30 seconds or until the transaction is confirmed. """ new_account = Account() # Allocate memory for the account balance_needed = Token.get_min_balance_rent_for_exempt_for_account( self._conn) # Construct transaction txn = Transaction() txn.add( sp.create_account( sp.CreateAccountParams( from_pubkey=self.payer.public_key(), new_account_pubkey=new_account.public_key(), lamports=balance_needed, space=ACCOUNT_LAYOUT.sizeof(), program_id=self.program_id, ))) txn.add( spl_token.initialize_account( spl_token.InitializeAccountParams( account=new_account.public_key(), mint=self.pubkey, owner=owner, program_id=self.program_id))) # Send the two instructions self._conn.send_transaction(txn, self.payer, new_account, opts=TxOpts( skip_preflight=True, skip_confirmation=skip_confirmation)) return new_account.public_key()
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 add_signer(self, signer: Account) -> None: """Fill in a signature for a partially signed Transaction. The `signer` must be the corresponding `Account` for a `PublicKey` that was previously provided to `signPartial` """ signed_msg = signer.sign(self.serialize_message()) self.add_signature(signer.public_key(), signed_msg.signature)
def test_settle_fund( bootstrapped_market: Market, stubbed_payer: Account, stubbed_quote_wallet: Account, stubbed_base_wallet: Account, ): open_order_accounts = bootstrapped_market.find_open_orders_accounts_for_owner( stubbed_payer.public_key()) for open_order_account in open_order_accounts: assert "error" not in bootstrapped_market.settle_funds( stubbed_payer, open_order_account, stubbed_base_wallet.public_key(), stubbed_quote_wallet.public_key(), opts=TxOpts(skip_confirmation=False), )
def test_transfer_signatures(stubbed_blockhash): """Test signing transfer transactions.""" acc1, acc2 = Account(), Account() transfer1 = sp.transfer( sp.TransferParams(from_pubkey=acc1.public_key(), to_pubkey=acc2.public_key(), lamports=123)) transfer2 = sp.transfer( sp.TransferParams(from_pubkey=acc2.public_key(), to_pubkey=acc1.public_key(), lamports=123)) txn = txlib.Transaction(recent_blockhash=stubbed_blockhash).add( transfer1, transfer2) txn.sign(acc1, acc2) expected = txlib.Transaction(recent_blockhash=stubbed_blockhash, signatures=txn.signatures).add( transfer1, transfer2) assert txn == expected
def make_cancel_order_by_client_id_instruction( self, owner: Account, open_orders_account: PublicKey, client_id: int) -> TransactionInstruction: return instructions.cancel_order_by_client_id( instructions.CancelOrderByClientIDParams( market=self.state.public_key(), owner=owner.public_key(), open_orders=open_orders_account, request_queue=self.state.request_queue(), client_id=client_id, program_id=self.state.program_id(), ))
def test_sign_partial(stubbed_blockhash): """Test paritally sigining a transaction.""" acc1, acc2 = Account(), Account() transfer = sp.transfer(sp.TransferParams(from_pubkey=acc1.public_key(), to_pubkey=acc2.public_key(), lamports=123)) partial_txn = txlib.Transaction(recent_blockhash=stubbed_blockhash).add(transfer) partial_txn.sign_partial(acc1, acc2.public_key()) assert len(partial_txn.signature()) == txlib.SIG_LENGTH assert len(partial_txn.signatures) == 2 assert not partial_txn.signatures[1].signature partial_txn.add_signer(acc2) expected_txn = txlib.Transaction(recent_blockhash=stubbed_blockhash).add(transfer) expected_txn.sign(acc1, acc2) assert partial_txn == expected_txn
def _create_mint_args( conn: Union[Client, AsyncClient], payer: Account, mint_authority: PublicKey, decimals: int, program_id: PublicKey, freeze_authority: Optional[PublicKey], skip_confirmation: bool, balance_needed: int, cls: Union[Type[Token], Type[AsyncToken]], ) -> Tuple[Union[Token, AsyncToken], Transaction, Account, Account, TxOpts]: mint_account = Account() token = cls(conn, mint_account.public_key(), program_id, payer) # type: ignore # 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, ))) return token, txn, payer, mint_account, TxOpts( skip_confirmation=skip_confirmation, skip_preflight=True)
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)
def test_generate_account_from_secret_key(): """Generate an account with provided secret key.""" secret_key = bytes( [ 153, 218, 149, 89, 225, 94, 145, 62, 233, 171, 46, 83, 227, 223, 173, 87, 93, 163, 59, 73, 190, 17, 37, 187, 146, 46, 51, 73, 79, 73, 136, 40, ] ) acc = Account(secret_key) assert str(acc.public_key()) == "2q7pyhPwAwZ3QMfZrnAbDhnh9mDUqycszcpf86VgQxhF"
def settle_funds( # pylint: disable=too-many-arguments self, owner: Account, open_orders: OpenOrdersAccount, base_wallet: PublicKey, quote_wallet: PublicKey, # TODO: add referrer_quote_wallet. opts: TxOpts = TxOpts(), ) -> RPCResponse: # TODO: Handle wrapped sol accounts if open_orders.owner != owner.public_key(): raise Exception("Invalid open orders account") vault_signer = PublicKey.create_program_address( [ bytes(self.state.public_key()), self.state.vault_signer_nonce().to_bytes(8, byteorder="little") ], self.state.program_id(), ) transaction = Transaction() transaction.add( self.make_settle_funds_instruction(open_orders, base_wallet, quote_wallet, vault_signer)) return self._conn.send_transaction(transaction, owner, opts=opts)
def _create_wrapped_native_account_args( program_id: PublicKey, owner: PublicKey, payer: Account, amount: int, skip_confirmation: bool, balance_needed: int, ) -> Tuple[PublicKey, Transaction, Account, Account, TxOpts]: new_account = Account() # Allocate memory for the account # Construct transaction txn = Transaction() txn.add( sp.create_account( sp.CreateAccountParams( from_pubkey=payer.public_key(), new_account_pubkey=new_account.public_key(), lamports=balance_needed, space=ACCOUNT_LAYOUT.sizeof(), program_id=program_id, ))) txn.add( sp.transfer( sp.TransferParams(from_pubkey=payer.public_key(), to_pubkey=new_account.public_key(), lamports=amount))) txn.add( spl_token.initialize_account( spl_token.InitializeAccountParams( account=new_account.public_key(), mint=WRAPPED_SOL_MINT, owner=owner, program_id=program_id))) return new_account.public_key(), txn, payer, new_account, TxOpts( skip_confirmation=skip_confirmation)
quote_ccy = pair.split("/")[0] quote_ccy_mint = {} for mkt in get_token_mints(): quote_ccy_mint.update({mkt.name: mkt.address}) print("Token Mint is: {}".format(quote_ccy_mint[quote_ccy])) # %% # Get private key and use that the create a new account #pubkey = "GKksmU6hSJ2X7zz1mcE3Qhr7DDEpvxqbygzb17SxygUD" f = open('./my-solana-wallet/my-keypair.json') private_key = json.load(f) mid = len(private_key) // 2 private_key = private_key[:mid] # to 32 bytes payer = Account(private_key) # Your account to pay fees print("Public Key is: {}".format(payer.public_key())) # %% cc = conn("https://api.mainnet-beta.solana.com/") quote_token = Token( cc, pubkey=PublicKey(quote_ccy_mint[quote_ccy]), # mint address of token program_id=TOKEN_PROGRAM_ID, payer=payer, ) quote_wallet = quote_token.create_account( payer.public_key(), skip_confirmation=False) # Make sure you send tokens to this address
def test_order_placement_cancellation_cycle( bootstrapped_market: Market, stubbed_payer: Account, stubbed_quote_wallet: Account, stubbed_base_wallet: Account, ): initial_request_len = len(bootstrapped_market.load_request_queue()) bootstrapped_market.place_order( payer=stubbed_quote_wallet.public_key(), owner=stubbed_payer, side=Side.Buy, order_type=OrderType.Limit, limit_price=1000, max_quantity=3000, opts=TxOpts(skip_confirmation=False), ) request_queue = bootstrapped_market.load_request_queue() # 0 request after matching. assert len(request_queue) == initial_request_len + 1 # There should be no bid order. bids = bootstrapped_market.load_bids() assert sum(1 for _ in bids) == 0 # There should be no ask order. asks = bootstrapped_market.load_asks() assert sum(1 for _ in asks) == 0 bootstrapped_market.place_order( payer=stubbed_base_wallet.public_key(), owner=stubbed_payer, side=Side.Sell, order_type=OrderType.Limit, limit_price=1500, max_quantity=3000, opts=TxOpts(skip_confirmation=False), ) # The two order shouldn't get executed since there is a price difference of 1 bootstrapped_market.match_orders( stubbed_payer, 2, opts=TxOpts(skip_confirmation=False), ) # There should be 1 bid order that we sent earlier. bids = bootstrapped_market.load_bids() assert sum(1 for _ in bids) == 1 # There should be 1 ask order that we sent earlier. asks = bootstrapped_market.load_asks() assert sum(1 for _ in asks) == 1 for bid in bids: bootstrapped_market.cancel_order(stubbed_payer, bid, opts=TxOpts(skip_confirmation=False)) bootstrapped_market.match_orders(stubbed_payer, 1, opts=TxOpts(skip_confirmation=False)) # All bid order should have been cancelled. bids = bootstrapped_market.load_bids() assert sum(1 for _ in bids) == 0 for ask in asks: bootstrapped_market.cancel_order(stubbed_payer, ask, opts=TxOpts(skip_confirmation=False)) bootstrapped_market.match_orders(stubbed_payer, 1, opts=TxOpts(skip_confirmation=False)) # All ask order should have been cancelled. asks = bootstrapped_market.load_asks() assert sum(1 for _ in asks) == 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 GridStrategy(object): def __init__(self, upper: float, lower: float, amount: float, grid: int, pair: str, base: str, quote: str, owner: str, private: str): """ :params upper: price up :params lower: price down :params amount: amount of the order :params grid: amount of grid :params pair: dexlab trading pair address :params base: youur base coin address for trading :params quote: your quote coin address for trading :params owner: your solana wallet address :params private: your private key for pay the transaction gas """ self.upper = upper self.lower = lower self.amount = amount self.grid = grid self.pair = pair self.base = base self.quote = quote self.owner = owner self.key = base58.b58decode(private) self.payer = Account(self.key[:32]) self.client = Client('', '') self.cc = conn('https://api.mainnet-beta.solana.com/') self.market = Market.load( self.cc, PublicKey(self.pair), program_id=PublicKey( '9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin')) try: self.open_acc = self.market.find_open_orders_accounts_for_owner( self.payer.public_key())[0].address except: self.open_acc = '' self.base_decimal = self.market.state.base_spl_token_decimals() self.quote_decimal = self.market.state.quote_spl_token_decimals() print(f'Initialize...\n\n' f'----parameters----\n\n' f'upper: {self.upper}\n' f'lower: {self.lower}\n' f'amount: {self.amount}\n' f'grid: {self.grid}\n' f'base decimal: {self.base_decimal}\n' f'quote decimal: {self.quote_decimal}\n' f'pair: {self.pair}\n' f'base: {self.base}\n' f'quote: {self.quote}\n' f'owner: {self.owner}\n' f'open orders account: {self.open_acc}\n' f'key: {self.key[:32]}\n\n' f'----start----\n') def _get_orders(self): """ :return: a dict contains price and client id Ex: {price: client} """ orders = self.market.load_orders_for_owner(PublicKey(self.owner)) order_table = {} for o in orders: order_table[o.client_id] = o.info.price return order_table def _get_last_price(self): """ :return: last price (float) """ return float( self.client.get_public_single_market_price(self.pair)['price']) def _buy_func(self, price, client_id): self.market.place_order(payer=PublicKey(self.base), owner=self.payer, side=Side.BUY, order_type=OrderType.LIMIT, limit_price=price, max_quantity=abs(self.amount), client_id=client_id, opts=TxOpts(skip_preflight=True)) print( f'Client ID: {client_id}; Price {price}; Amount: {self.amount}; Open: BUY' ) def _sell_func(self, price, client_id): self.market.place_order(payer=PublicKey(self.quote), owner=self.payer, side=Side.SELL, order_type=OrderType.LIMIT, limit_price=price, max_quantity=abs(self.amount), client_id=client_id, opts=TxOpts(skip_preflight=True)) print( f'Client ID: {client_id}; Price {price}; Amount: {self.amount}; Open: SELL' ) def cancel_order(self, client_id): """ :return: a dict contains tx_hash and id """ self.open_acc = self.market.find_open_orders_accounts_for_owner( self.payer.public_key())[0].address return self.market.cancel_order_by_client_id( self.payer, PublicKey(self.open_acc), client_id, TxOpts(skip_preflight=True)) def cancel_pending(self): order_table = self._get_orders() for o in order_table.keys(): self.cancel_order(o) def on_exit(self): if True: print(f'----Exit----\n\n' f'Closing all open orders...\n') self.cancel_pending() print('----Success----') def update_order(self, order_table, distance, last_prcie): for i in range(self.grid): if (i + 1) not in order_table: if (self.lower + i * distance) < last_prcie: #self._buy_func(round((self.lower + i * distance), self.base_decimal), i + 1) print( f'Client ID: {i + 1}; Price {round((self.lower + i * distance), self.base_decimal)}; Amount: {self.amount}; Open: BUY' ) elif (self.lower + i * distance) > last_prcie: #self._sell_func(round((self.lower + i * distance), self.quote_decimal), i + 1) print( f'Client ID: {i + 1}; Price {round((self.lower + i * distance), self.quote_decimal)}; Amount: {self.amount}; Open: SELL' ) def griding(self): """ Main Logic """ distance = (self.upper - self.lower) / self.grid order_table = self._get_orders() last_prcie = self._get_last_price() print(f'Current Price: {last_prcie}\n') print('----place orders----') self.update_order(order_table, distance, last_prcie)
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 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 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)