def send_transaction( self, txn: Transaction, *signers: Account, opts: types.TxOpts = types.TxOpts() ) -> types.RPCResponse: """Send a transaction. :param txn: Transaction object. :param signers: Signers to sign the transaction. :param opts: (optional) Transaction options. >>> from solana.account import Account >>> from solana.system_program import TransferParams, transfer >>> from solana.transaction import Transaction >>> sender, reciever = Account(1), Account(2) >>> txn = Transaction().add(transfer(TransferParams( ... from_pubkey=sender.public_key(), to_pubkey=reciever.public_key(), lamports=1000))) >>> solana_client = Client("http://localhost:8899") >>> solana_client.send_transaction(txn, sender) # doctest: +SKIP {'jsonrpc': '2.0', 'result': '236zSA5w4NaVuLXXHK1mqiBuBxkNBu84X6cfLBh1v6zjPrLfyECz4zdedofBaZFhs4gdwzSmij9VkaSo2tR5LTgG', 'id': 12} """ try: # TODO: Cache recent blockhash blockhash_resp = self.get_recent_blockhash() if not blockhash_resp["result"]: raise RuntimeError("failed to get recent blockhash") txn.recent_blockhash = Blockhash(blockhash_resp["result"]["value"]["blockhash"]) except Exception as err: raise RuntimeError("failed to get recent blockhash") from err txn.sign(*signers) return self.send_raw_transaction(txn.serialize(), opts=opts)
def send_raw_transaction(self, txn: Union[bytes, str], opts: types.TxOpts = types.TxOpts()) -> types.RPCResponse: """Send a transaction that has already been signed and serialized into the wire format. :param txn: Fully-signed Transaction object, a fully sign transaction in wire format, or a fully transaction as base-64 encoded string. :param opts: (optional) Transaction options. Before submitting, the following preflight checks are performed (unless disabled with the `skip_preflight` option): - The transaction signatures are verified. - The transaction is simulated against the latest max confirmed bank and on failure an error will be returned. Preflight checks may be disabled if desired. >>> solana_client = Client("http://localhost:8899") >>> full_signed_tx_str = ( ... "AbN5XM+qw+7oOLsFw7goQSLBis7c1kXJFP6OF4w7YmQNhhbQYcyBiybKuOzzhV7McvoRP3Mey9AhXojtwDCdbwoBAAEDE5j2" ... "LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8poq0Z3/7HyiU3QphU8Ix1F7ENq5TrmAUnb4V8y5LhwPwAAAAAAAAAAAAAA" ... "AAAAAAAAAAAAAAAAAAAAAAAAAAAAg5YY9wG6fpuieuWYJd1ta7ZtFPbV0OriFRYdcYUaEGkBAgIAAQwCAAAAQEIPAAAAAAA=") >>> solana_client.send_raw_transaction(full_signed_tx_str) # doctest: +SKIP {'jsonrpc': '2.0', 'result': 'CMwyESM2NE74mghfbvsHJDERF7xMYKshwwm6VgH6GFqXzx8LfBFuP5ruccumfhTguha6seUHPpiHzzHUQXzq2kN', 'id': 1} """ # noqa: E501 # pylint: disable=line-too-long args = self._send_raw_transaction_args(txn, opts) resp = self._provider.make_request(*args) if opts.skip_confirmation: return self._post_send(resp, self._provider) post_send_args = self._send_raw_transaction_post_send_args(resp, opts) return self.__post_send_with_confirm(*post_send_args)
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)
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)