1

I just need some direction in figuring out how to simulate a buy/sell transaction of an spl token.

example token: G33s1LiUADEBLzN5jL6ocSXqrT2wsUq9W6nZ8o4k1b4L

i've messed around with solana-py/solders and haven't had too much luck. been wanting to try mostly with just the json rpc methods but haven't had much luck figuring this out that way either.

from chatting with chatgpt, i have bits and pieces but am obviously missing some stuff.

I can make a new keypair, get the associated token address for the spl token and newly created wallet, get the latest block hash, just actually making the transaction/serializing/deserializing/etc is what i'm stuck on

in solders i see instructions.py which has different params: transferparams, transfercheckedparams, various mint params. which one would i use? or how would i make a transaction not using a 3rd party library?

just confused and would like some guidance, thanks.


edit - current code:
getting BlockhashNotFound / AccountNotFound error

import requests
import json

solana_rpc = 'https://api.mainnet-beta.solana.com'
token_mint_address = '2adFTbyzVwMwPtgV68DUnrfdwB6tTAJiiVxJ6D8nwiEG'

from solders.keypair import Keypair

keypair = Keypair()
wallet = keypair.pubkey()
secret = keypair.secret()

def get_jup_quote(input_mint: str = "So11111111111111111111111111111111111111112", output_mint: str = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", amount: int = 0) -> dict:
    """
    required params:
    inputMint = Input token mint address: str
    outputMint = Output token mint address: str
    amount = token amount: int
    """
    jup_quote_url = 'https://quote-api.jup.ag/v6/quote'
    # params = {
    #     'inputMint': 'So11111111111111111111111111111111111111112',
    #     'outputMint': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', #usdc
    #     'amount': '1000000',
    #     'slippageBps': '1', # optional
    # }
    params = {
        'inputMint': input_mint,
        'outputMint': output_mint,
        'amount': amount
    }
    response = requests.get(url=jup_quote_url, params=params)
    return response.json()

quote = get_jup_quote(
    output_mint='2adFTbyzVwMwPtgV68DUnrfdwB6tTAJiiVxJ6D8nwiEG',
    amount=int(point_one_percent_supply)
)

{'inputMint': 'So11111111111111111111111111111111111111112',
 'inAmount': '385772346489',
 'outputMint': '2adFTbyzVwMwPtgV68DUnrfdwB6tTAJiiVxJ6D8nwiEG',
 'outAmount': '56461414044909573',
 'otherAmountThreshold': '56179106974685026',
 'swapMode': 'ExactIn',
 'slippageBps': 50,
 'platformFee': None,
 'priceImpactPct': '0.2191461341568245261456741333',
 'routePlan': [{'swapInfo': {'ammKey': '4c7bJ8D1JoU1mXzzc5vdgtz7GkR3CoWK62myDdPgVH5W',
    'label': 'Raydium',
    'inputMint': 'So11111111111111111111111111111111111111112',
    'outputMint': '2adFTbyzVwMwPtgV68DUnrfdwB6tTAJiiVxJ6D8nwiEG',
    'inAmount': '385772346489',
    'outAmount': '56461414044909573',
    'feeAmount': '964430866',
    'feeMint': 'So11111111111111111111111111111111111111112'},
   'percent': 100}],
 'contextSlot': 0,
 'timeTaken': 0.223854177}

def get_serialized_tx(user_public_key: str, quote_response: dict, wrap_and_unwrap_sol: bool = True) -> dict:
    """
    required params:
    userPublicKey = The user public key: str
    quoteResponse = The object that is returned from the Quote API: quote response
    """
    jup_swap_url = 'https://quote-api.jup.ag/v6/swap'
    headers = {'Content-Type': 'application/json'}
    if not isinstance(user_public_key, str):
        user_public_key = str(user_public_key)
    data = {
        "quoteResponse": quote_response,
        "userPublicKey": user_public_key,
        "wrapAndUnwrapSol": wrap_and_unwrap_sol
    }
    response = requests.post(url=jup_swap_url, headers=headers, json=data)
    return response.json()

serialized_tx = get_serialized_tx(
    user_public_key=wallet,
    quote_response=quote
)
serialized_tx

{'swapTransaction': 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAJDvqeJn6oaX1hlU7gubozBLZz8chY5lIeTx/oWCTvsNtuVwTMQLtDVDuJnIQejidD4jo8BTzmqZMD/xfURc9XkqtY72d/tWNeZHNyS3Dha2QFVANOpHocez/NiIU8QV0yVL56Nm6pO4WeLALbKAlrl8kwRG7FG8lq16XTqMrIoFjD45VkLpNML+s9j669THy+yrrJ/6q525A2LCJzU9DjhooAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMGRm/lIRcy/+ytunLDm+e8jOW7xfcSayxDmzpAAAAABHnVW/IxwG7udMVuzmgVB/2xst6j9I5RArHNola8E48Gm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpF3jXQF1NiylIZPXAQSiFPa4fnUXhT1LBUTnViFcek+U6uJA/tzXKscZ8Wa9IV+32Gwr4MqUKfFnjIZGeDsipvIyXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZtD/6J/XX9kp0wJsfKVh53ksJqzbfyd1RSzIap7OM5eiLuFcvuqdjWWHrqWhPCT5YX/tR/0/hxvoZx2q7gzMYHQgGAAUCwFwVAAYACQMEFwEAAAAAAAwGAAEACAUJAQEFAgABDAIAAAB53NLRWQAAAAkBAQERDAYAAwAKBQkBAQcfCQsAAQIEAwgKBwcNBxoJDxkQEhEYFw4VExYUGwIECyTBIJszQdacgQQBAAAAB2QAAXnc0tFZAAAABcCpX1uXyAAyAAAJAwEAAAEJAUdMda1JAn3/OD1AcneYrVGZ9AQe8oPW2CMqoawUfIZ7CjxzdHI2Ozo3Pj8EDgsKPQ==',
 'lastValidBlockHeight': 229709721,
 'prioritizationFeeLamports': 99999}

swap_transaction = serialized_tx.get('swapTransaction')

def simulate_transaction(tx):
    headers = {
        'Content-Type': 'application/json',
    }

    data = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "simulateTransaction",
        "params": [
            swap_transaction,
            {
                "encoding":"base64",
                "replaceRecentBlockhash": True
            }
        ]
    }

    response = requests.post(url=solana_rpc, headers=headers, json=data)
    return response.json()

test = simulate_transaction(swap_transaction)

{'jsonrpc': '2.0',
 'result': {'context': {'apiVersion': '1.17.21', 'slot': 249015932},
  'value': {'accounts': None,
   'err': 'AccountNotFound',
   'logs': [],
   'returnData': None,
   'unitsConsumed': 0}},
 'id': 1}

1 Answer 1

1

You can easily transfer tokens using Solana.py. However swapping tokens using Raydium for example is not implemented in Solana.py or Solders. You can refer to Jupiter Swap API Docs, the examples are given in Javascript, but you can try converting them to Python.

If you want to transfer tokens simply using Solana.py, then you can refer to this test example

You can either use transferparams and transfercheckedparams. Difference between them is that transfer checked requires you to pass the token's mint and decimals, and if you enter the wrong token mint or decimal, then transaction would fail. This acts as an additional check to ensure you're sending the right token amount based on its decimals.

3
  • i'm trying to simulate a swap - so a buy/sell of an spl token. i'll have the correct token mint address and decimals. so i should serialize a swap transaction using the jupiter api and then use that serialized tx in the simulateTransaction rpc method?
    – user9116
    Feb 18 at 6:33
  • yes , that should work. Feb 18 at 13:51
  • getting either BlockhashNotFound or AccountNotFound depending on if i add "replaceRecentBlockhash": True to the simulateTransaction params. i have updated the op with my current process, can u take a look?
    – user9116
    Feb 18 at 21:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.