async def create_stake(client: AsyncClient, payer: Keypair, stake: Keypair, authority: PublicKey, lamports: int): print(f"Creating stake {stake.public_key}") resp = await client.get_minimum_balance_for_rent_exemption(STAKE_LEN) txn = Transaction() txn.add( sys.create_account( sys.CreateAccountParams( from_pubkey=payer.public_key, new_account_pubkey=stake.public_key, lamports=resp['result'] + lamports, space=STAKE_LEN, program_id=STAKE_PROGRAM_ID, ))) txn.add( st.initialize( st.InitializeParams(stake=stake.public_key, authorized=Authorized( staker=authority, withdrawer=authority, ), lockup=Lockup( unix_timestamp=0, epoch=0, custodian=sys.SYS_PROGRAM_ID, )))) await client.send_transaction(txn, payer, stake, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
async def deposit_sol( client: AsyncClient, funder: Keypair, stake_pool_address: PublicKey, destination_token_account: PublicKey, amount: int, ): resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) txn = Transaction() txn.add( sp.deposit_sol( sp.DepositSolParams( program_id=STAKE_POOL_PROGRAM_ID, stake_pool=stake_pool_address, withdraw_authority=withdraw_authority, reserve_stake=stake_pool.reserve_stake, funding_account=funder.public_key, destination_pool_account=destination_token_account, manager_fee_account=stake_pool.manager_fee_account, referral_pool_account=destination_token_account, pool_mint=stake_pool.pool_mint, system_program_id=sys.SYS_PROGRAM_ID, token_program_id=stake_pool.token_program_id, amount=amount, deposit_authority=None, ) ) ) await client.send_transaction( txn, funder, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
def make_combined_transaction(self, storage, steps, msg, instruction): print("make_combined_transaction") trx = Transaction() trx.add(self.sol_instr_keccak(make_keccak_instruction_data(1, len(msg), 13))) trx.add(self.sol_instr_partial_call_or_continue(storage, steps, instruction)) print(trx.__dict__) return trx
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)
async def create_mint(client: AsyncClient, payer: Keypair, mint: Keypair, mint_authority: PublicKey): mint_balance = await AsyncToken.get_min_balance_rent_for_exempt_for_mint( client) print(f"Creating pool token mint {mint.public_key}") txn = Transaction() txn.add( sys.create_account( sys.CreateAccountParams( from_pubkey=payer.public_key, new_account_pubkey=mint.public_key, lamports=mint_balance, space=MINT_LAYOUT.sizeof(), program_id=TOKEN_PROGRAM_ID, ))) txn.add( spl_token.initialize_mint( spl_token.InitializeMintParams( program_id=TOKEN_PROGRAM_ID, mint=mint.public_key, decimals=9, mint_authority=mint_authority, freeze_authority=None, ))) await client.send_transaction(txn, payer, mint, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
def liquidate(self, group: Group, margin_account: MarginAccount, prices: typing.List[TokenValue]) -> typing.Optional[str]: instruction_builders = self.prepare_instructions( group, margin_account, prices) if len(instruction_builders) == 0: return None transaction = Transaction() for builder in instruction_builders: transaction.add(builder.build()) for instruction in transaction.instructions: self.logger.debug("INSTRUCTION") self.logger.debug(" Keys:") for key in instruction.keys: self.logger.debug(" ", f"{key.pubkey}".ljust(45), f"{key.is_signer}".ljust(6), f"{key.is_writable}".ljust(6)) self.logger.debug(" Data:", " ".join(f"{x:02x}" for x in instruction.data)) self.logger.debug(" Program ID:", instruction.program_id) transaction_response = self.context.client.send_transaction( transaction, self.wallet.account) transaction_id = self.context.unwrap_transaction_id_or_raise_exception( transaction_response) return transaction_id
def transfer(params: TransferParams) -> Transaction: """Generate a Transaction that transfers lamports from one account to another. >>> from solana.publickey import PublicKey >>> sender, reciever = PublicKey(1), PublicKey(2) >>> transfer_tx = transfer( ... TransferParams(from_pubkey=sender, to_pubkey=reciever, lamports=1000) ... ) >>> type(transfer_tx) <class 'solana.transaction.Transaction'> """ layout = SYSTEM_INSTRUCTION_LAYOUTS[_TRANSFER] data = encode_data(layout, params.lamports) txn = Transaction() txn.add( TransactionInstruction( keys=[ AccountMeta(pubkey=params.from_pubkey, is_signer=True, is_writable=True), AccountMeta(pubkey=params.to_pubkey, is_signer=False, is_writable=True), ], program_id=sys_program_id(), data=data, )) return txn
async def create_vote(client: AsyncClient, payer: Keypair, vote: Keypair, node: Keypair, voter: PublicKey, withdrawer: PublicKey, commission: int): print(f"Creating vote account {vote.public_key}") resp = await client.get_minimum_balance_for_rent_exemption(VOTE_STATE_LEN) txn = Transaction() txn.add( sys.create_account( sys.CreateAccountParams( from_pubkey=payer.public_key, new_account_pubkey=vote.public_key, lamports=resp['result'], space=VOTE_STATE_LEN, program_id=VOTE_PROGRAM_ID, ))) txn.add( initialize( InitializeParams( vote=vote.public_key, rent_sysvar=SYSVAR_RENT_PUBKEY, clock_sysvar=SYSVAR_CLOCK_PUBKEY, node=node.public_key, authorized_voter=voter, authorized_withdrawer=withdrawer, commission=commission, ))) await client.send_transaction(txn, payer, vote, node, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
def _create_multisig_args( self, m: int, signers: List[PublicKey], balance_needed: int, ) -> Tuple[Transaction, Keypair, Keypair]: multisig_keypair = Keypair() txn = Transaction() txn.add( sp.create_account( sp.CreateAccountParams( from_pubkey=self.payer.public_key, new_account_pubkey=multisig_keypair.public_key, lamports=balance_needed, space=MULTISIG_LAYOUT.sizeof(), program_id=self.program_id, ) ) ) txn.add( spl_token.initialize_multisig( spl_token.InitializeMultisigParams( program_id=self.program_id, multisig=multisig_keypair.public_key, m=m, signers=signers, ) ) ) return txn, self.payer, multisig_keypair
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), )
async def withdraw_sol( client: AsyncClient, owner: Keypair, source_token_account: PublicKey, stake_pool_address: PublicKey, destination_system_account: PublicKey, amount: int, ): resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) txn = Transaction() txn.add( sp.withdraw_sol( sp.WithdrawSolParams( program_id=STAKE_POOL_PROGRAM_ID, stake_pool=stake_pool_address, withdraw_authority=withdraw_authority, source_transfer_authority=owner.public_key, source_pool_account=source_token_account, reserve_stake=stake_pool.reserve_stake, destination_system_account=destination_system_account, manager_fee_account=stake_pool.manager_fee_account, pool_mint=stake_pool.pool_mint, clock_sysvar=SYSVAR_CLOCK_PUBKEY, stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, stake_program_id=STAKE_PROGRAM_ID, token_program_id=stake_pool.token_program_id, amount=amount, sol_withdraw_authority=None, ) ) ) await client.send_transaction( txn, owner, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
def _create_perm_accounts(self, seed_list): tx = Transaction() stage_list = [ NeonCreatePermAccount(self._s, seed, STORAGE_SIZE) for seed in seed_list ] account_list = [s.sol_account for s in stage_list] info_list = self._s.solana.get_account_info_list(account_list) balance = self._s.solana.get_multiple_rent_exempt_balances_for_size( [STORAGE_SIZE])[0] for account, stage in zip(info_list, stage_list): if not account: stage.balance = balance stage.build() tx.add(stage.tx) elif account.lamports < balance: raise RuntimeError(f"insufficient balance") elif PublicKey(account.owner) != PublicKey(EVM_LOADER_ID): raise RuntimeError(f"wrong owner") elif account.tag not in {EMPTY_STORAGE_TAG, FINALIZED_STORAGE_TAG}: raise RuntimeError(f"not empty, not finalized") rid = self._resource.rid opkey = str(self._resource.public_key()) if len(tx.instructions): self.debug(f"Create new accounts for resource {opkey}:{rid}") SolTxListSender(self._s, [tx], NeonCreatePermAccount.NAME).send() else: self.debug(f"Use existing accounts for resource {opkey}:{rid}") return account_list
def createERC20TokenAccountTrx(self, token_info) -> Transaction: trx = Transaction() trx.add( TransactionInstruction( program_id=EVM_LOADER_ID, data=bytes.fromhex('0F'), keys=[ AccountMeta(pubkey=self.operator_account, is_signer=True, is_writable=True), AccountMeta(pubkey=PublicKey(token_info["key"]), is_signer=False, is_writable=True), AccountMeta(pubkey=PublicKey(token_info["owner"]), is_signer=False, is_writable=True), AccountMeta(pubkey=PublicKey(token_info["contract"]), is_signer=False, is_writable=True), AccountMeta(pubkey=PublicKey(token_info["mint"]), is_signer=False, is_writable=True), AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), ])) return trx
def build_tx(self) -> Transaction: tx = Transaction() if not self._skip_create_account: tx.add(self.s.create_account_tx) tx.add( self.s.builder.make_noniterative_call_transaction( len(tx.instructions))) return tx
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 make_noniterative_call_transaction(self, length_before: int = 0 ) -> Transaction: trx = Transaction() trx.add( self.make_keccak_instruction(length_before + 1, len(self.eth_trx.unsigned_msg()), 5)) trx.add(self.make_05_call_instruction()) return trx
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 make_partial_call_or_continue_transaction(self, steps=0, length_before=0 ) -> Transaction: trx = Transaction() trx.add( self.make_keccak_instruction(length_before + 1, len(self.eth_trx.unsigned_msg()), 13)) trx.add(self.make_partial_call_or_continue_instruction(steps)) return trx
def create_storage_account(self, seed): storage = PublicKey(sha256(bytes(self.acc.public_key()) + bytes(seed, 'utf8') + bytes(PublicKey(EVM_LOADER))).digest()) print("Storage", storage) if getBalance(storage) == 0: trx = Transaction() trx.add(createAccountWithSeed(self.acc.public_key(), self.acc.public_key(), seed, 10**9, 128*1024, PublicKey(EVM_LOADER))) send_transaction(client, trx, self.acc) return storage
def call_begin(self, storage, steps, msg, instruction): print("Begin") trx = Transaction() trx.add( self.sol_instr_keccak( self, make_keccak_instruction_data(1, len(msg), 13))) trx.add( self.sol_instr_19_partial_call(self, storage, steps, instruction)) print(trx.__dict__) return send_transaction(client, trx, self.acc)
async def create_associated_token_account(client: AsyncClient, payer: Keypair, owner: PublicKey, mint: PublicKey) -> PublicKey: txn = Transaction() create_txn = spl_token.create_associated_token_account( payer=payer.public_key, owner=owner, mint=mint) txn.add(create_txn) await client.send_transaction(txn, payer, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) return create_txn.keys[1].pubkey
def _create_associated_token_account_args( self, owner: PublicKey, skip_confirmation: bool, ) -> Tuple[PublicKey, Transaction, Keypair, TxOpts]: # Construct transaction txn = Transaction() create_txn = spl_token.create_associated_token_account( payer=self.payer.public_key, owner=owner, mint=self.pubkey ) txn.add(create_txn) return create_txn.keys[1].pubkey, txn, self.payer, TxOpts(skip_confirmation=skip_confirmation)
async def decrease_validator_stake( client: AsyncClient, payer: Keypair, staker: Keypair, stake_pool_address: PublicKey, validator_vote: PublicKey, lamports: int ): resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) resp = await client.get_account_info(stake_pool.validator_list, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) validator_info = next(x for x in validator_list.validators if x.vote_account_address == validator_vote) (validator_stake, _) = find_stake_program_address( STAKE_POOL_PROGRAM_ID, validator_info.vote_account_address, stake_pool_address, ) transient_stake_seed = validator_info.transient_seed_suffix_start + 1 # bump up by one to avoid reuse (transient_stake, _) = find_transient_stake_program_address( STAKE_POOL_PROGRAM_ID, validator_info.vote_account_address, stake_pool_address, transient_stake_seed, ) txn = Transaction() txn.add( sp.decrease_validator_stake( sp.DecreaseValidatorStakeParams( program_id=STAKE_POOL_PROGRAM_ID, stake_pool=stake_pool_address, staker=staker.public_key, withdraw_authority=withdraw_authority, validator_list=stake_pool.validator_list, validator_stake=validator_stake, transient_stake=transient_stake, clock_sysvar=SYSVAR_CLOCK_PUBKEY, rent_sysvar=SYSVAR_RENT_PUBKEY, system_program_id=sys.SYS_PROGRAM_ID, stake_program_id=STAKE_PROGRAM_ID, lamports=lamports, transient_stake_seed=transient_stake_seed, ) ) ) signers = [payer, staker] if payer != staker else [payer] await client.send_transaction( txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
def create_associated_token_account(self, owner: PublicKey, payer: SolanaAccount): # Construct transaction # This part of code is based on original implementation of Token.create_associated_token_account # except that skip_preflight is set to True txn = Transaction() create_txn = spl_token.create_associated_token_account( payer=payer.public_key(), owner=owner, mint=self.token.pubkey) txn.add(create_txn) self.token._conn.send_transaction(txn, payer, opts=TxOpts(skip_preflight=True, skip_confirmation=False)) return create_txn.keys[1].pubkey
async def test_program_subscribe( test_http_client_async: AsyncClient, websocket: SolanaWsClientProtocol, program_subscribed: Tuple[PublicKey, PublicKey], ): """Test program subscription.""" program, owned = program_subscribed instruction = sp.assign( sp.AssignParams(account_pubkey=owned.public_key, program_id=program.public_key)) transaction = Transaction() transaction.add(instruction) await test_http_client_async.send_transaction(transaction, owned) main_resp = await websocket.recv() assert main_resp.result.value.pubkey == owned.public_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_if_needed(self, ether_addr: Union[str, EthereumAddress]): token_account = self.get_token_account_address(ether_addr) info = self.solana.get_account_info(token_account) if info is not None: return token_account txn = Transaction() create_txn = spl_token.create_associated_token_account( payer=self.signer.public_key(), owner=PublicKey(ether2program(ether_addr)[0]), mint=self.token_mint) txn.add(create_txn) SolTxListSender(self, [txn], 'CreateAssociatedTokenAccount(1)', skip_preflight=True).send() return token_account
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()
async def delegate_stake(client: AsyncClient, payer: Keypair, staker: Keypair, stake: PublicKey, vote: PublicKey): txn = Transaction() txn.add( st.delegate_stake( st.DelegateStakeParams( stake=stake, vote=vote, clock_sysvar=SYSVAR_CLOCK_PUBKEY, stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, stake_config_id=SYSVAR_STAKE_CONFIG_ID, staker=staker.public_key, ))) signers = [payer, staker] if payer != staker else [payer] await client.send_transaction(txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))
async def authorize(client: AsyncClient, payer: Keypair, authority: Keypair, stake: PublicKey, new_authority: PublicKey, stake_authorize: StakeAuthorize): txn = Transaction() txn.add( st.authorize( st.AuthorizeParams( stake=stake, clock_sysvar=SYSVAR_CLOCK_PUBKEY, authority=authority.public_key, new_authority=new_authority, stake_authorize=stake_authorize, ))) signers = [payer, authority] if payer != authority else [payer] await client.send_transaction(txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed))