solana-py
solana-py copied to clipboard
Transaction failed to sanitize accounts offsets correctly on SPL transfer
This is send_solana_to_single(). It works with solder + raw
def send_solana_to_single(self, from_address, to_address, sol_amount, signer_keypairs=[]):
if not from_address:
from_address = self.keypair.pubkey()
elif from_address and isinstance(from_address, str):
from_address = Pubkey.from_string(from_address)
if isinstance(to_address, str):
to_address = Pubkey.from_string(to_address)
if not signer_keypairs:
signer_keypairs = [self.keypair]
transaction = Transaction()
sol_transfer_params = SolTransferParams(from_pubkey=from_address, to_pubkey=to_address, lamports=sol_to_lamport(sol_amount))
sol_transfer_instruction = SolTransfer(sol_transfer_params)
transaction.add(sol_transfer_instruction)
transaction = transaction.to_solders()
blockhash = self.client.retryable_get_latest_blockhash_value()
transaction.sign(signer_keypairs, blockhash.blockhash)
signature = self.client.retryable_send_raw_transaction(transaction)
return signature
I implement similar for spl
def send_spl_to_single(self, from_address, to_address, spl_address, spl_amount, signer_keypairs=[]):
if not from_address:
from_address = self.keypair.pubkey()
elif from_address and isinstance(from_address, str):
from_address = Pubkey.from_string(from_address)
if isinstance(to_address, str):
to_address = Pubkey.from_string(to_address)
if isinstance(spl_address, str):
spl_address = Pubkey.from_string(spl_address)
if not signer_keypairs:
signer_keypairs = [self.keypair]
for n in range(3):
account_info = self.client.retryable_get_account_info_json_parsed(spl_address)
parsed_account_info = AccountInfoParser(account_info, spl_address)
if parsed_account_info.valid_account_info:
break
elif n == 3:
raise ValueError(f"Cant find account info for spl token {spl_address}")
if parsed_account_info.account_type == 'TOKEN_ACCOUNT' and parsed_account_info.owner == Constants.TOKEN_PROGRAM_ID:
from_address_ata = get_associated_token_address(from_address, spl_address)
to_address_ata = get_associated_token_address(to_address, spl_address)
program_id = Constants.TOKEN_PROGRAM_ID
elif parsed_account_info.account_type == 'TOKEN_ACCOUNT' and parsed_account_info.owner == Constants.TOKEN_2022_PROGRAM_ID:
from_address_ata = None
to_address_ata = None
program_id = Constants.TOKEN_2022_PROGRAM_ID
else:
print(f"SPL address is wrong type {spl_address} {parsed_account_info.account_type}")
raise ValueError
# Check if to_address ATA exists, if not create them
all_spl = self.get_all_spl(to_address) #token_client.get_token_accounts_by_owner does same thing
if not (str(spl_address) in all_spl):
print(f"Creating associated token account for {to_address}")
token_manager = TokenManager(self.client)
token_manager.create_associated_token_account(spl_address, program_id, signer_keypairs, to_address)
if isinstance(program_id, str):
program_id = Pubkey.from_string(program_id)
transaction = Transaction()
spl_transfer_params = SplTransferCheckedParams(
program_id=program_id,
source=from_address_ata,
mint=spl_address,
dest=to_address_ata,
owner=signer_keypairs[0].pubkey(),
amount=spl_amount,
decimals=all_spl[str(spl_address)]['decimals'] #checked uses decimals
)
spl_transfer_instruction = SplTransferChecked(spl_transfer_params)
transaction.add(spl_transfer_instruction)
signature = self.client.retryable_send_transaction(transaction, signer_keypairs[0])
#transaction = transaction.to_solders()
#blockhash = self.client.retryable_get_latest_blockhash_value()
#transaction.sign(signer_keypairs, blockhash.blockhash)
#signature = self.client.retryable_send_raw_transaction(transaction)
return signature
It works when I use retryable_send_transaction. I am doing it in devnet
>>> sent
SendTransactionResp(
Signature(
445CE2jpJEMEfvvKygjyvf9h79CSnQ8N6KyP756jeU73Ve6JZeH9uN37VSKAUCJCbqss6yB15KdQp34TSzgLCPgH,
),
)
but when i use retryable_send_raw_transaction
#signature = self.client.retryable_send_transaction(transaction, signer_keypairs[0])
transaction = transaction.to_solders()
blockhash = self.client.retryable_get_latest_blockhash_value()
transaction.sign(signer_keypairs, blockhash.blockhash)
signature = self.client.retryable_send_raw_transaction(transaction)
return signature
I get
results = solana_client.send_raw_transaction(signed_transaction, opts=tx_opts)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/usr/local/lib/python3.11/dist-packages/solana/rpc/api.py", line 996, in send_raw_transaction\n return self._post_send(resp)\n ^^^^^^^^^^^^^^^^^^^^^\n File "/usr/local/lib/python3.11/dist-packages/solana/rpc/core.py", line 511, in _post_send\n raise RPCNoResultException(resp.message)\nsolana.rpc.core.RPCNoResultException: invalid transaction: Transaction failed to sanitize accounts offsets correctly