michaelhly / solana-py

Solana Python SDK
https://michaelhly.github.io/solana-py
MIT License
1.04k stars 273 forks source link

cannot convert 'Transaction' object to bytes #457

Closed andredif closed 2 weeks ago

andredif commented 2 weeks ago

HI, I can't successfully create a

import asyncio
import json
import base64
import struct
import base58
import hashlib
import websockets
import time

from solana.rpc.async_api import AsyncClient
from solana.transaction import Transaction
from solana.rpc.commitment import Confirmed
from solana.rpc.types import TxOpts

from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.instruction import Instruction, AccountMeta
from solders.system_program import TransferParams, transfer
from solders.transaction import VersionedTransaction

from spl.token.instructions import get_associated_token_address
import spl.token.instructions as spl_token

from config import *

from construct import Struct, Int64ul, Flag

async def buy_token(mint: Pubkey, bonding_curve: Pubkey, associated_bonding_curve: Pubkey, amount: float, slippage: float = 0.01, max_retries=5):
    private_key = base58.b58decode(PRIVATE_KEY)
    payer = Keypair.from_bytes(private_key)

    async with AsyncClient(RPC_ENDPOINT) as client:
        associated_token_account = get_associated_token_address(payer.pubkey(), mint)
        amount_lamports = int(amount * LAMPORTS_PER_SOL)

        # Fetch the token price
        curve_state = await get_pump_curve_state(client, bonding_curve)
        token_price_sol = calculate_pump_curve_price(curve_state)
        token_amount = amount / token_price_sol

        # Calculate maximum SOL to spend with slippage
        max_amount_lamports = int(amount_lamports * (1 + slippage))

        # Create associated token account with retries
        for ata_attempt in range(max_retries):
            # try:
            account_info = await client.get_account_info(associated_token_account)
            if account_info.value is None:
                print(f"Creating associated token account (Attempt {ata_attempt + 1})...")
                create_ata_ix = spl_token.create_associated_token_account(
                    payer=payer.pubkey(),
                    owner=payer.pubkey(),
                    mint=mint
                )
                print(f"Payer address {payer.pubkey()}")
                create_ata_tx = Transaction()
                create_ata_tx.add(create_ata_ix)
                recent_blockhash = await client.get_latest_blockhash()
                create_ata_tx.recent_blockhash = recent_blockhash.value.blockhash
                print(f"no erroe before sending")
                await client.send_transaction(create_ata_tx, payer)
                print("Associated token account created.")
                print(f"Associated token account address: {associated_token_account}")
                break
            else:
                print("Associated token account already exists.")
                print(f"Associated token account address: {associated_token_account}")
                break
            # except Exception as e:
            #     print(f"Attempt {ata_attempt + 1} to create associated token account failed: {str(e)}")
            #     if ata_attempt < max_retries - 1:
            #         wait_time = 2 ** ata_attempt
            #         print(f"Retrying in {wait_time} seconds...")
            #         await asyncio.sleep(wait_time)
            #     else:
            #         print("Max retries reached. Unable to create associated token account.")
            #         return

        # Continue with the buy transaction
        for attempt in range(max_retries):
            try:
                accounts = [
                    AccountMeta(pubkey=PUMP_GLOBAL, is_signer=False, is_writable=False),
                    AccountMeta(pubkey=PUMP_FEE, is_signer=False, is_writable=True),
                    AccountMeta(pubkey=mint, is_signer=False, is_writable=False),
                    AccountMeta(pubkey=bonding_curve, is_signer=False, is_writable=True),
                    AccountMeta(pubkey=associated_bonding_curve, is_signer=False, is_writable=True),
                    AccountMeta(pubkey=associated_token_account, is_signer=False, is_writable=True),
                    AccountMeta(pubkey=payer.pubkey(), is_signer=True, is_writable=True),
                    AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False),
                    AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, is_signer=False, is_writable=False),
                    AccountMeta(pubkey=SYSTEM_RENT, is_signer=False, is_writable=False),
                    AccountMeta(pubkey=PUMP_EVENT_AUTHORITY, is_signer=False, is_writable=False),
                    AccountMeta(pubkey=PUMP_PROGRAM, is_signer=False, is_writable=False),
                ]

                discriminator = struct.pack("<Q", 16927863322537952870)
                data = discriminator + struct.pack("<Q", int(token_amount * 10**6)) + struct.pack("<Q", max_amount_lamports)
                buy_ix = Instruction(PUMP_PROGRAM, data, accounts)

                recent_blockhash = await client.get_latest_blockhash()
                transaction = Transaction()
                transaction.add(buy_ix)
                transaction.recent_blockhash = recent_blockhash.value.blockhash

                tx = await client.send_transaction(
                    transaction,
                    payer,
                    opts=TxOpts(skip_preflight=True, preflight_commitment=Confirmed),
                )

                print(f"Transaction sent: https://explorer.solana.com/tx/{tx.value}")

                await client.confirm_transaction(tx.value, commitment="confirmed")
                print("Transaction confirmed")
                return tx.value

            except Exception as e:
                print(f"Attempt {attempt + 1} failed: {str(e)}")
                if attempt < max_retries - 1:
                    wait_time = 2 ** attempt
                    print(f"Retrying in {wait_time} seconds...")
                    await asyncio.sleep(wait_time)
                else:
                    print("Max retries reached. Unable to complete the transaction.")

The error is always Cannot convert 'Transaction' object to bytes, it happens in the send_transaction function of the client. Is it a bug?

andredif commented 2 weeks ago

I downgraded from solana==0.35 to 0.34 and code works

michaelhly commented 2 weeks ago

For legacy transactions, you need to use https://michaelhly.com/solana-py/rpc/api/#solana.rpc.api.Client.send_legacy_transaction instead of send_transaction.

Or you can migrate from from solana.transaction import Transaction to from solders.transaction import Transaction