Add the full code

This commit is contained in:
Ake
2024-09-09 09:04:23 +07:00
parent db959fc08c
commit dcd8475920
24 changed files with 4457 additions and 0 deletions
+277
View File
@@ -0,0 +1,277 @@
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
# Here and later all the discriminators are precalculated. See learning-examples/discriminator.py
EXPECTED_DISCRIMINATOR = struct.pack("<Q", 6966180631402821399)
TOKEN_DECIMALS = 6
class BondingCurveState:
_STRUCT = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag
)
def __init__(self, data: bytes) -> None:
parsed = self._STRUCT.parse(data[8:])
self.__dict__.update(parsed)
async def get_pump_curve_state(conn: AsyncClient, curve_address: Pubkey) -> BondingCurveState:
response = await conn.get_account_info(curve_address)
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
data = response.value.data
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return BondingCurveState(data)
def calculate_pump_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (curve_state.virtual_token_reserves / 10 ** TOKEN_DECIMALS)
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
)
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
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.")
def load_idl(file_path):
with open(file_path, 'r') as f:
return json.load(f)
def decode_create_instruction(ix_data, ix_def, accounts):
args = {}
offset = 8 # Skip 8-byte discriminator
for arg in ix_def['args']:
if arg['type'] == 'string':
length = struct.unpack_from('<I', ix_data, offset)[0]
offset += 4
value = ix_data[offset:offset+length].decode('utf-8')
offset += length
elif arg['type'] == 'publicKey':
value = base64.b64encode(ix_data[offset:offset+32]).decode('utf-8')
offset += 32
else:
raise ValueError(f"Unsupported type: {arg['type']}")
args[arg['name']] = value
# Add accounts
args['mint'] = str(accounts[0])
args['bondingCurve'] = str(accounts[2])
args['associatedBondingCurve'] = str(accounts[3])
args['user'] = str(accounts[7])
return args
async def listen_for_create_transaction(websocket):
idl = load_idl('idl/pump_fun_idl.json')
create_discriminator = 8576854823835016728
subscription_message = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "blockSubscribe",
"params": [
{"mentionsAccountOrProgram": str(PUMP_PROGRAM)},
{
"commitment": "confirmed",
"encoding": "base64",
"showRewards": False,
"transactionDetails": "full",
"maxSupportedTransactionVersion": 0
}
]
})
await websocket.send(subscription_message)
print(f"Subscribed to blocks mentioning program: {PUMP_PROGRAM}")
ping_interval = 20
last_ping_time = time.time()
while True:
try:
current_time = time.time()
if current_time - last_ping_time > ping_interval:
await websocket.ping()
last_ping_time = current_time
response = await asyncio.wait_for(websocket.recv(), timeout=30)
data = json.loads(response)
if 'method' in data and data['method'] == 'blockNotification':
if 'params' in data and 'result' in data['params']:
block_data = data['params']['result']
if 'value' in block_data and 'block' in block_data['value']:
block = block_data['value']['block']
if 'transactions' in block:
for tx in block['transactions']:
if isinstance(tx, dict) and 'transaction' in tx:
tx_data_decoded = base64.b64decode(tx['transaction'][0])
transaction = VersionedTransaction.from_bytes(tx_data_decoded)
for ix in transaction.message.instructions:
if str(transaction.message.account_keys[ix.program_id_index]) == str(PUMP_PROGRAM):
ix_data = bytes(ix.data)
discriminator = struct.unpack('<Q', ix_data[:8])[0]
if discriminator == create_discriminator:
create_ix = next(instr for instr in idl['instructions'] if instr['name'] == 'create')
account_keys = [str(transaction.message.account_keys[index]) for index in ix.accounts]
decoded_args = decode_create_instruction(ix_data, create_ix, account_keys)
return decoded_args
except asyncio.TimeoutError:
print("No data received for 30 seconds, sending ping...")
await websocket.ping()
last_ping_time = time.time()
except websockets.exceptions.ConnectionClosed:
print("WebSocket connection closed. Reconnecting...")
raise
async def main(yolo_mode=False):
if yolo_mode:
while True:
try:
async with websockets.connect(WSS_ENDPOINT) as websocket:
while True:
try:
await trade(websocket)
except websockets.exceptions.ConnectionClosed:
print("WebSocket connection closed. Reconnecting...")
break
except Exception as e:
print(f"An error occurred: {e}")
print("Waiting for 5 seconds before looking for the next token...")
await asyncio.sleep(5)
except Exception as e:
print(f"Connection error: {e}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
else:
await trade()
if __name__ == "__main__":
asyncio.run(main())
+26
View File
@@ -0,0 +1,26 @@
from solders.pubkey import Pubkey
# System & pump.fun addresses
PUMP_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
PUMP_GLOBAL = Pubkey.from_string("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf")
PUMP_EVENT_AUTHORITY = Pubkey.from_string("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1")
PUMP_FEE = Pubkey.from_string("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM")
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
SYSTEM_RENT = Pubkey.from_string("SysvarRent111111111111111111111111111111111")
SOL = Pubkey.from_string("So11111111111111111111111111111111111111112")
LAMPORTS_PER_SOL = 1_000_000_000
# Trading parameters
BUY_AMOUNT = 0.0001 # Amount of SOL to spend when buying
BUY_SLIPPAGE = 0.2 # 20% slippage tolerance for buying
SELL_SLIPPAGE = 0.2 # 20% slippage tolerance for selling
# Your nodes
# You can also get a trader node https://docs.chainstack.com/docs/warp-transactions
RPC_ENDPOINT = "SOLANA_NODE_RPC_ENDPOINT"
WSS_ENDPOINT = "SOLANA_NODE_WSS_ENDPOINT"
#Private key
PRIVATE_KEY = "SOLANA_PRIVATE_KEY"
+662
View File
@@ -0,0 +1,662 @@
{
"version": "0.1.0",
"name": "pump",
"instructions": [
{
"name": "initialize",
"docs": [
"Creates the global state."
],
"accounts": [
{
"name": "global",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{
"name": "setParams",
"docs": [
"Sets the global state parameters."
],
"accounts": [
{
"name": "global",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "feeRecipient",
"type": "publicKey"
},
{
"name": "initialVirtualTokenReserves",
"type": "u64"
},
{
"name": "initialVirtualSolReserves",
"type": "u64"
},
{
"name": "initialRealTokenReserves",
"type": "u64"
},
{
"name": "tokenTotalSupply",
"type": "u64"
},
{
"name": "feeBasisPoints",
"type": "u64"
}
]
},
{
"name": "create",
"docs": [
"Creates a new coin and bonding curve."
],
"accounts": [
{
"name": "mint",
"isMut": true,
"isSigner": true
},
{
"name": "mintAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "mplTokenMetadata",
"isMut": false,
"isSigner": false
},
{
"name": "metadata",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "associatedTokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "rent",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "name",
"type": "string"
},
{
"name": "symbol",
"type": "string"
},
{
"name": "uri",
"type": "string"
}
]
},
{
"name": "buy",
"docs": [
"Buys tokens from a bonding curve."
],
"accounts": [
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "feeRecipient",
"isMut": true,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedUser",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "rent",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "amount",
"type": "u64"
},
{
"name": "maxSolCost",
"type": "u64"
}
]
},
{
"name": "sell",
"docs": [
"Sells tokens into a bonding curve."
],
"accounts": [
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "feeRecipient",
"isMut": true,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedUser",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "associatedTokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "amount",
"type": "u64"
},
{
"name": "minSolOutput",
"type": "u64"
}
]
},
{
"name": "withdraw",
"docs": [
"Allows the admin to withdraw liquidity for a migration once the bonding curve completes"
],
"accounts": [
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedUser",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "rent",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": []
}
],
"accounts": [
{
"name": "Global",
"type": {
"kind": "struct",
"fields": [
{
"name": "initialized",
"type": "bool"
},
{
"name": "authority",
"type": "publicKey"
},
{
"name": "feeRecipient",
"type": "publicKey"
},
{
"name": "initialVirtualTokenReserves",
"type": "u64"
},
{
"name": "initialVirtualSolReserves",
"type": "u64"
},
{
"name": "initialRealTokenReserves",
"type": "u64"
},
{
"name": "tokenTotalSupply",
"type": "u64"
},
{
"name": "feeBasisPoints",
"type": "u64"
}
]
}
},
{
"name": "BondingCurve",
"type": {
"kind": "struct",
"fields": [
{
"name": "virtualTokenReserves",
"type": "u64"
},
{
"name": "virtualSolReserves",
"type": "u64"
},
{
"name": "realTokenReserves",
"type": "u64"
},
{
"name": "realSolReserves",
"type": "u64"
},
{
"name": "tokenTotalSupply",
"type": "u64"
},
{
"name": "complete",
"type": "bool"
}
]
}
}
],
"events": [
{
"name": "CreateEvent",
"fields": [
{
"name": "name",
"type": "string",
"index": false
},
{
"name": "symbol",
"type": "string",
"index": false
},
{
"name": "uri",
"type": "string",
"index": false
},
{
"name": "mint",
"type": "publicKey",
"index": false
},
{
"name": "bondingCurve",
"type": "publicKey",
"index": false
},
{
"name": "user",
"type": "publicKey",
"index": false
}
]
},
{
"name": "TradeEvent",
"fields": [
{
"name": "mint",
"type": "publicKey",
"index": false
},
{
"name": "solAmount",
"type": "u64",
"index": false
},
{
"name": "tokenAmount",
"type": "u64",
"index": false
},
{
"name": "isBuy",
"type": "bool",
"index": false
},
{
"name": "user",
"type": "publicKey",
"index": false
},
{
"name": "timestamp",
"type": "i64",
"index": false
},
{
"name": "virtualSolReserves",
"type": "u64",
"index": false
},
{
"name": "virtualTokenReserves",
"type": "u64",
"index": false
}
]
},
{
"name": "CompleteEvent",
"fields": [
{
"name": "user",
"type": "publicKey",
"index": false
},
{
"name": "mint",
"type": "publicKey",
"index": false
},
{
"name": "bondingCurve",
"type": "publicKey",
"index": false
},
{
"name": "timestamp",
"type": "i64",
"index": false
}
]
},
{
"name": "SetParamsEvent",
"fields": [
{
"name": "feeRecipient",
"type": "publicKey",
"index": false
},
{
"name": "initialVirtualTokenReserves",
"type": "u64",
"index": false
},
{
"name": "initialVirtualSolReserves",
"type": "u64",
"index": false
},
{
"name": "initialRealTokenReserves",
"type": "u64",
"index": false
},
{
"name": "tokenTotalSupply",
"type": "u64",
"index": false
},
{
"name": "feeBasisPoints",
"type": "u64",
"index": false
}
]
}
],
"errors": [
{
"code": 6000,
"name": "NotAuthorized",
"msg": "The given account is not authorized to execute this instruction."
},
{
"code": 6001,
"name": "AlreadyInitialized",
"msg": "The program is already initialized."
},
{
"code": 6002,
"name": "TooMuchSolRequired",
"msg": "slippage: Too much SOL required to buy the given amount of tokens."
},
{
"code": 6003,
"name": "TooLittleSolReceived",
"msg": "slippage: Too little SOL received to sell the given amount of tokens."
},
{
"code": 6004,
"name": "MintDoesNotMatchBondingCurve",
"msg": "The mint does not match the bonding curve."
},
{
"code": 6005,
"name": "BondingCurveComplete",
"msg": "The bonding curve has completed and liquidity migrated to raydium."
},
{
"code": 6006,
"name": "BondingCurveNotComplete",
"msg": "The bonding curve has not completed."
},
{
"code": 6007,
"name": "NotInitialized",
"msg": "The program is not initialized."
}
],
"metadata": {
"address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
}
}
@@ -0,0 +1,414 @@
{
"transaction": [
"AgJ5wlQKptQK5lR1rKuLex98aANgrofIxDKh4bYcGBMqRrxspLReufQPA/MY9iyOBRs9J9ZAJvcIpuUzlP8lRQYKgV5owXDiYc0bAtKwtbffRx+4AujjJwkjulgWBz/08YbOU0cmqeRb3AUlhjOE5TkvHJGGT6D7X77Jpbxh9soDgAIAChL2MdL3xlA70bgIpTlRVYJ5yU7c4gCGkVyzuRpXUJYvmr5Oab9+zoJi5E/7feiMCGSkHpgBjBAk2HT/Omepbi/vvCtXBl7x3WZUML5ga6ZZbAKVMBut74ta/EEBQVD0EnQ7v7zcho+rNAKa57FiZ8EqFb32kF/Udj9NCpqzDWcquz307oLnDRm67n4w0qFL1j/3+kqE89q4xc3YQSOLLomVa8GPpVJkRHOYFAgQ5WYKuVxAmb0NVDhLEkMsLPLU/zvJ9WOIIMD9HQRJCq0s/CX00AY27y+Miq5i8Ng5rck8jK0R5qT8KUSk+oJRvvgVQm4b+yjGtmRmd2B8atn1ZqZGAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFW4PaTZlrPRNsVaL8XW6pRicuX9dL/O2VdK7b9bRiwBsXBzmONJWfSZGiwXrlR0aKNzG4SNIK1xnUUl3DmK/I6hl5p7g9UgMq89mNX5NwvGNWNRcHqdIn7NyPZeTxypgtwZbHj0XxFOJ1Sf2sEw81YuGxzGqD9tUm20bwD+ClGBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WQan1RcZLFxRIYzJTD1K8X9Y2u4Im6H9ROPb2YoAAAAArPE26wH8HE6IPSPItYRKtZo39mrdV8XprDtT4FnTXGTKXRcVnMiLdm8v4gNxeTkclw+K5btmaK2siraOY9HdQAYIAAUCkNADAAkCAAIMAgAAAAAJPQAAAAAACAAJA6BoBgAAAAAACg4BCwMEDA0FAAkODxARCmEYHsgoBRwHdwMAAABkb2QDAAAARE9ERwAAAGh0dHBzOi8vY2YtaXBmcy5jb20vaXBmcy9RbVkxbTJvd2hqQlp6eTFNdGhZbVdpbjNYd0dpbUdLV0M1WndOWFBDYmJhQjFrDwYABgABCQ4ACgwMBwEDBAYACQ4QEQoYZgY9EgHa6+op661VhCIAAMCDOEIAAAAAAA==",
"base64"
],
"meta": {
"err": null,
"status": {
"Ok": null
},
"fee": 115000,
"preBalances": [
1299959000,
0,
20558783,
0,
0,
0,
0,
297249326667618,
1,
1,
1141440,
323296939,
2500000,
1141440,
934087680,
731913600,
1009200,
0
],
"postBalances": [
162455200,
1461600,
24558783,
1101231920,
2039280,
15616720,
2039280,
297249337667618,
1,
1,
1141440,
323296939,
2500000,
1141440,
934087680,
731913600,
1009200,
0
],
"innerInstructions": [
{
"index": 3,
"instructions": [
{
"programIdIndex": 9,
"accounts": [
0,
1
],
"data": "11114XtYk9gGfZoo968fyjNUYQJKf9gdmkGoaoBpzFv4vyaSMBn3VKxZdv7mZLzoyX5YNC",
"stackHeight": 2
},
{
"programIdIndex": 14,
"accounts": [
1
],
"data": "2zt6UCCHp66bJGRS4G7bTsjdxFh6FQ9sBEyRfGyPQKxYisAw",
"stackHeight": 2
},
{
"programIdIndex": 9,
"accounts": [
0,
3
],
"data": "11112npZeiggj74jpdjnyaoXKQznZSuR59vRrSV7vxdg9g2eRJ4seDwRwaQLDUqBNSEnrB",
"stackHeight": 2
},
{
"programIdIndex": 15,
"accounts": [
0,
4,
3,
1,
9,
14
],
"data": "1",
"stackHeight": 2
},
{
"programIdIndex": 14,
"accounts": [
1
],
"data": "84eT",
"stackHeight": 3
},
{
"programIdIndex": 9,
"accounts": [
0,
4
],
"data": "11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL",
"stackHeight": 3
},
{
"programIdIndex": 14,
"accounts": [
4
],
"data": "P",
"stackHeight": 3
},
{
"programIdIndex": 14,
"accounts": [
4,
1
],
"data": "6R9wJMnJhbG9ZQYKJuVP2PB6vT2C61iaQx6VwGbPagDmk",
"stackHeight": 3
},
{
"programIdIndex": 13,
"accounts": [
5,
1,
11,
0,
11,
9
],
"data": "sCA7VhscVFkCjwGP776CKweeQ17GA3y6hoefZyQZ7igmWRvSXA49qEc3vT7wBUxVA13HoHqvXDFZ4UuibYrj1fSiqN7Hw2T1PxZfuF1ebruak4VwaCoseJMTaoCSRGbUZZSf",
"stackHeight": 2
},
{
"programIdIndex": 9,
"accounts": [
0,
5
],
"data": "3Bxs4bhMrSrmPkVD",
"stackHeight": 3
},
{
"programIdIndex": 9,
"accounts": [
5
],
"data": "9krTDUMpjBo4wxLP",
"stackHeight": 3
},
{
"programIdIndex": 9,
"accounts": [
5
],
"data": "SYXsBkG6yKW2wWDcW8EDHR6D3P82bKxJGPpM65DD8nHqBfMP",
"stackHeight": 3
},
{
"programIdIndex": 14,
"accounts": [
1,
4,
11
],
"data": "6ApXSNCamGdm",
"stackHeight": 2
},
{
"programIdIndex": 14,
"accounts": [
1,
11
],
"data": "31tb",
"stackHeight": 2
},
{
"programIdIndex": 10,
"accounts": [
17
],
"data": "7iazyA59wwtAStxsqtCeosLjmdhF7YPNeRh62abjnRpjo8BFJQyM79SCTR8EdrQNP4pFWzB9LRwFM7eYmn6zhAZ8UjEWrgARNaSmjuLGwaXuB6CQiRHZ2XpENVyDtB5adZ2hqDvmbGzTNsMd9CvgKxusSLTGhhW5Y7b4jvGji585fx1Bq3XKBg6Zr1mCNjcVFzQ45dRSbDad9ZQaVjDLSHMRVuwNvhvLM3RQCJLhyo4e6S156JeFmweeAp7HqHvGw3fVitNxwbrmnU8MsJ9",
"stackHeight": 2
}
]
},
{
"index": 4,
"instructions": [
{
"programIdIndex": 14,
"accounts": [
1
],
"data": "84eT",
"stackHeight": 2
},
{
"programIdIndex": 9,
"accounts": [
0,
6
],
"data": "11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL",
"stackHeight": 2
},
{
"programIdIndex": 14,
"accounts": [
6
],
"data": "P",
"stackHeight": 2
},
{
"programIdIndex": 14,
"accounts": [
6,
1
],
"data": "6dhk2iczksvz6s1rFHcSMywmmwmB1z7XmGVUbnAVDoyj7",
"stackHeight": 2
}
]
},
{
"index": 5,
"instructions": [
{
"programIdIndex": 14,
"accounts": [
4,
6,
3
],
"data": "3LUFBVrqeiX9",
"stackHeight": 2
},
{
"programIdIndex": 9,
"accounts": [
0,
3
],
"data": "3Bxs3zyALUmzCtNB",
"stackHeight": 2
},
{
"programIdIndex": 9,
"accounts": [
0,
7
],
"data": "3Bxs4Z7Wb6tTKEWB",
"stackHeight": 2
},
{
"programIdIndex": 10,
"accounts": [
17
],
"data": "2K7nL28PxCW8ejnyCeuMpbXaZKMjMgWS9mpWYzdhxxxazMRueEhr8dhzoSv8cJB4QmssgbcPVf7uHyA7xpBWFRc9qBGRzEzUtR1t2P8uGyxRepqEGGoak55qnosFUyXaDoRPdY3r2GR952e4KnxiYyGBD4epcJmcs5akyXSEueVSCuYxtXDaCp7HgAoy",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Create",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeMint2",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2780 of 238190 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1595 of 212794 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 206181 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4214 of 202297 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 21990 of 219769 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [2]",
"Program log: IX: Create Metadata Accounts v3",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Allocate space for the account",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Assign the account to the owning program",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s consumed 37631 of 181110 compute units",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: MintTo",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4492 of 140964 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: SetAuthority",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2911 of 134325 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 127301 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: G3KpTd7rY3YDAAAAZG9kAwAAAERPREcAAABodHRwczovL2NmLWlwZnMuY29tL2lwZnMvUW1ZMW0yb3doakJaenkxTXRoWW1XaW4zWHdHaW1HS1dDNVp3TlhQQ2JiYUIxa75Oab9+zoJi5E/7feiMCGSkHpgBjBAk2HT/Omepbi/vO7+83IaPqzQCmuexYmfBKhW99pBf1HY/TQqasw1nKrv2MdL3xlA70bgIpTlRVYJ5yU7c4gCGkVyzuRpXUJYvmg==",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 126103 of 249550 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 118084 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 111497 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 107617 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20301 of 123447 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Buy",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 81505 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 69417 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe6+Tmm/fs6CYuRP+33ojAhkpB6YAYwQJNh0/zpnqW4v7wCrkEEAAAAAKeutVYQiAAAB9jHS98ZQO9G4CKU5UVWCeclO3OIAhpFcs7kaV1CWL5oKQsNmAAAAAABXtD0HAAAA1yQq8l6tAwAAq5BBAAAAANeMF6bNrgIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 37457 of 103146 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"
],
"preTokenBalances": [],
"postTokenBalances": [
{
"accountIndex": 4,
"mint": "Dosp4t6w5kDzAgBQBMEsZSUNzdwTC5zHYiVZQqMKpump",
"uiTokenAmount": {
"uiAmount": 962048231.511255,
"decimals": 6,
"amount": "962048231511255",
"uiAmountString": "962048231.511255"
},
"owner": "52EdRamuJQsj94DnpLBguCfXx8cGbyJiFBL5n1hmP5Ln",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"accountIndex": 6,
"mint": "Dosp4t6w5kDzAgBQBMEsZSUNzdwTC5zHYiVZQqMKpump",
"uiTokenAmount": {
"uiAmount": 37951768.488745,
"decimals": 6,
"amount": "37951768488745",
"uiAmountString": "37951768.488745"
},
"owner": "Ha3MnRTxb5iGbXkjCTF2VyLPSsbCaNG4ZaJkHaoQWqJ9",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
],
"rewards": null,
"loadedAddresses": {
"writable": [],
"readonly": []
},
"computeUnitsConsumed": 184311
},
"version": 0
}
@@ -0,0 +1,66 @@
import asyncio
import hashlib
import json
import os
import sys
import websockets
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from config import WSS_ENDPOINT, PUMP_PROGRAM
async def save_transaction(tx_data, tx_signature):
os.makedirs("blockSubscribe-transactions", exist_ok=True)
hashed_signature = hashlib.sha256(tx_signature.encode()).hexdigest()
file_path = os.path.join("blockSubscribe-transactions", f"{hashed_signature}.json")
with open(file_path, 'w') as f:
json.dump(tx_data, f, indent=2)
print(f"Saved transaction: {hashed_signature[:8]}...")
async def listen_for_transactions():
async with websockets.connect(WSS_ENDPOINT) as websocket:
subscription_message = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "blockSubscribe",
"params": [
{"mentionsAccountOrProgram": str(PUMP_PROGRAM)},
{
"commitment": "confirmed",
"encoding": "base64",
"showRewards": False,
"transactionDetails": "full",
"maxSupportedTransactionVersion": 0
}
]
})
await websocket.send(subscription_message)
print(f"Subscribed to blocks mentioning program: {PUMP_PROGRAM}")
while True:
try:
response = await websocket.recv()
data = json.loads(response)
if 'method' in data and data['method'] == 'blockNotification':
if 'params' in data and 'result' in data['params']:
block_data = data['params']['result']
if 'value' in block_data and 'block' in block_data['value']:
block = block_data['value']['block']
if 'transactions' in block:
transactions = block['transactions']
for tx in transactions:
if isinstance(tx, dict) and 'transaction' in tx:
if isinstance(tx['transaction'], list) and len(tx['transaction']) > 0:
tx_signature = tx['transaction'][0]
elif isinstance(tx['transaction'], dict) and 'signatures' in tx['transaction']:
tx_signature = tx['transaction']['signatures'][0]
else:
continue
await save_transaction(tx, tx_signature)
elif 'result' in data:
print(f"Subscription confirmed")
except Exception as e:
print(f"An error occurred: {str(e)}")
if __name__ == "__main__":
asyncio.run(listen_for_transactions())
@@ -0,0 +1,31 @@
import hashlib
import struct
# https://book.anchor-lang.com/anchor_bts/discriminator.html
# Set the instruction name here
instruction_name = "account:BondingCurve"
def calculate_discriminator(instruction_name):
# Create a SHA256 hash object
sha = hashlib.sha256()
# Update the hash with the instruction name
sha.update(instruction_name.encode('utf-8'))
# Get the first 8 bytes of the hash
discriminator_bytes = sha.digest()[:8]
# Convert the bytes to a 64-bit unsigned integer (little-endian)
discriminator = struct.unpack('<Q', discriminator_bytes)[0]
return discriminator
# Calculate the discriminator for the specified instruction
discriminator = calculate_discriminator(instruction_name)
print(f"Discriminator for '{instruction_name}' instruction: {discriminator}")
# global:buy discriminator - 16927863322537952870
# global:sell discriminator - 12502976635542562355
# global:create discriminator - 8576854823835016728
# account:BondingCurve discriminator - 6966180631402821399
@@ -0,0 +1,132 @@
import base64
import json
import struct
import hashlib
from solana.transaction import Transaction
from solders.transaction import VersionedTransaction
from solders.pubkey import Pubkey
import sys
def load_idl(file_path):
with open(file_path, 'r') as f:
return json.load(f)
def load_transaction(file_path):
with open(file_path, 'r') as f:
data = json.load(f)
return data
def decode_instruction(ix_data, ix_def):
args = {}
offset = 8 # Skip 8-byte discriminator
for arg in ix_def['args']:
if arg['type'] == 'u64':
value = struct.unpack_from('<Q', ix_data, offset)[0]
offset += 8
elif arg['type'] == 'publicKey':
value = ix_data[offset:offset+32].hex()
offset += 32
elif arg['type'] == 'string':
length = struct.unpack_from('<I', ix_data, offset)[0]
offset += 4
value = ix_data[offset:offset+length].decode('utf-8')
offset += length
else:
raise ValueError(f"Unsupported type: {arg['type']}")
args[arg['name']] = value
return args
def calculate_discriminator(instruction_name):
sha = hashlib.sha256()
sha.update(instruction_name.encode('utf-8'))
discriminator_bytes = sha.digest()[:8]
discriminator = struct.unpack('<Q', discriminator_bytes)[0]
return discriminator
def decode_transaction(tx_data, idl):
decoded_instructions = []
# Decode the base64 transaction data
tx_data_decoded = base64.b64decode(tx_data['transaction'][0])
# Check if it's a versioned transaction
if tx_data.get('version') == 0:
# Use solders library for versioned transactions
transaction = VersionedTransaction.from_bytes(tx_data_decoded)
instructions = transaction.message.instructions
account_keys = transaction.message.account_keys
print("Versioned transaction detected")
else:
# Use legacy deserialization for older transactions
transaction = Transaction.deserialize(tx_data_decoded)
instructions = transaction.instructions
account_keys = transaction.message.account_keys
print("Legacy transaction detected")
print(f"Number of instructions: {len(instructions)}")
for idx, ix in enumerate(instructions):
program_id = str(account_keys[ix.program_id_index])
print(f"\nInstruction {idx}:")
print(f"Program ID: {program_id}")
print(f"IDL program address: {idl['metadata']['address']}")
if program_id == idl['metadata']['address']:
ix_data = bytes(ix.data)
discriminator = struct.unpack('<Q', ix_data[:8])[0]
print(f"Discriminator: {discriminator:016x}")
for idl_ix in idl['instructions']:
idl_discriminator = calculate_discriminator(f"global:{idl_ix['name']}")
print(f"Checking against IDL instruction: {idl_ix['name']} with discriminator {idl_discriminator:016x}")
if discriminator == idl_discriminator:
decoded_args = decode_instruction(ix_data, idl_ix)
accounts = [str(account_keys[acc_idx]) for acc_idx in ix.accounts]
decoded_instructions.append({
'name': idl_ix['name'],
'args': decoded_args,
'accounts': accounts,
'program': program_id
})
break
else:
decoded_instructions.append({
'name': 'Unknown',
'data': ix_data.hex(),
'accounts': [str(account_keys[acc_idx]) for acc_idx in ix.accounts],
'program': program_id
})
else:
instruction_name = 'External'
if program_id == 'ComputeBudget111111111111111111111111111111':
if ix.data[:1] == b'\x03':
instruction_name = 'ComputeBudget: Set compute unit limit'
elif ix.data[:1] == b'\x02':
instruction_name = 'ComputeBudget: Set compute unit price'
elif program_id == 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL':
instruction_name = 'Associated Token Account: Create'
decoded_instructions.append({
'name': instruction_name,
'programId': program_id,
'data': bytes(ix.data).hex(),
'accounts': [str(account_keys[acc_idx]) for acc_idx in ix.accounts]
})
return decoded_instructions
if len(sys.argv) != 2:
print("Usage: python decode_fromBlock.py <transaction_file_path>")
sys.exit(1)
tx_file_path = sys.argv[1]
idl = load_idl('../idl/pump_fun_idl.json')
tx_data = load_transaction(tx_file_path)
decoded_instructions = decode_transaction(tx_data, idl)
print(json.dumps(decoded_instructions, indent=2))
@@ -0,0 +1,56 @@
import json
import base64
import struct
from construct import Struct, Int64ul, Flag
LAMPORTS_PER_SOL = 1_000_000_000
TOKEN_DECIMALS = 6
EXPECTED_DISCRIMINATOR = struct.pack("<Q", 6966180631402821399)
class BondingCurveState:
_STRUCT = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag
)
def __init__(self, data: bytes) -> None:
parsed = self._STRUCT.parse(data[8:])
self.__dict__.update(parsed)
def calculate_bonding_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (curve_state.virtual_token_reserves / 10 ** TOKEN_DECIMALS)
def decode_bonding_curve_data(raw_data: str) -> BondingCurveState:
decoded_data = base64.b64decode(raw_data)
if decoded_data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return BondingCurveState(decoded_data)
# Load the JSON data
with open('raw_bondingCurve_from_getAccountInfo.json', 'r') as file:
json_data = json.load(file)
# Extract the base64 encoded data
encoded_data = json_data['result']['value']['data'][0]
# Decode the data
bonding_curve_state = decode_bonding_curve_data(encoded_data)
# Calculate and print the token price
token_price_sol = calculate_bonding_curve_price(bonding_curve_state)
print("Bonding Curve State:")
print(f" Virtual Token Reserves: {bonding_curve_state.virtual_token_reserves}")
print(f" Virtual SOL Reserves: {bonding_curve_state.virtual_sol_reserves}")
print(f" Real Token Reserves: {bonding_curve_state.real_token_reserves}")
print(f" Real SOL Reserves: {bonding_curve_state.real_sol_reserves}")
print(f" Token Total Supply: {bonding_curve_state.token_total_supply}")
print(f" Complete: {bonding_curve_state.complete}")
print(f"\nToken Price: {token_price_sol:.10f} SOL")
@@ -0,0 +1,100 @@
import json
import base58
from solana.transaction import Transaction
from solders.pubkey import Pubkey
import struct
import sys
import base64
import sys
if len(sys.argv) != 2:
print("Usage: python decode_getTransaction.py <transaction_file_path>")
sys.exit(1)
tx_file_path = sys.argv[1]
# Load the IDL
with open('../idl/pump_fun_idl.json', 'r') as f:
idl = json.load(f)
# Load the transaction log
with open(tx_file_path, 'r') as f:
tx_log = json.load(f)
# Extract the transaction data
tx_data = tx_log['result']['transaction']
print(json.dumps(tx_data, indent=2))
def decode_create_instruction(data):
# The Create instruction has 3 string arguments: name, symbol, uri
offset = 8 # Skip the 8-byte discriminator
results = []
for _ in range(3):
length = struct.unpack_from("<I", data, offset)[0]
offset += 4
string_data = data[offset:offset+length].decode('utf-8')
results.append(string_data)
offset += length
return {
"name": results[0],
"symbol": results[1],
"uri": results[2]
}
def decode_buy_instruction(data):
# Assuming the buy instruction has a u64 argument for amount
amount = struct.unpack_from("<Q", data, 8)[0]
return {"amount": amount}
def decode_instruction_data(instruction, accounts, data):
if instruction['name'] == 'create':
return decode_create_instruction(data)
elif instruction['name'] == 'buy':
return decode_buy_instruction(data)
else:
return f"Unhandled instruction type: {instruction['name']}"
def find_matching_instruction(accounts, data):
if 'instructions' not in idl:
print("Warning: No instructions found in IDL")
return None
for instruction in idl['instructions']:
if len(instruction['accounts']) == len(accounts):
return instruction
return None
# Parse the transaction
tx_message = tx_data['message']
instructions = tx_message['instructions']
for ix in instructions:
program_id = ix.get('programId')
accounts = ix.get('accounts', [])
data = ix.get('data', '')
if 'parsed' in ix:
print(f"Parsed instruction: {ix['program']} - {ix['parsed']['type']}")
print(f"Info: {json.dumps(ix['parsed']['info'], indent=2)}")
elif program_id == idl['metadata']['address']:
matching_instruction = find_matching_instruction(accounts, data)
if matching_instruction:
decoded_data = decode_instruction_data(matching_instruction, accounts, base58.b58decode(data))
print(f"Instruction: {matching_instruction['name']}")
print(f"Decoded data: {decoded_data}")
print("\nAccounts:")
for i, account in enumerate(accounts):
account_info = matching_instruction['accounts'][i]
print(f" {account_info['name']}: {account}")
else:
print(f"Unable to match instruction for program {program_id}")
else:
print(f"Instruction for program: {program_id}")
print(f"Data: {data}\n")
print("\nTransaction Information:")
print(f"Blockhash: {tx_message['recentBlockhash']}")
print(f"Fee payer: {tx_message['accountKeys'][0]['pubkey']}")
print(f"Signature: {tx_data['signatures'][0]}")
@@ -0,0 +1,215 @@
{
"message": {
"accountKeys": [
{
"pubkey": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "SysvarRent111111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"signer": false,
"source": "transaction",
"writable": false
}
],
"addressTableLookups": [],
"instructions": [
{
"accounts": [],
"data": "3JwEwun4YUPH",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [],
"data": "LEJDE7",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "AJTQ2h9DXrBqzdpEhcLVYocNoqujioBxb",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"11111111111111111111111111111111",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "5jRcjdixRUDSvSh4QXANSHU9rk2He2WMm",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"parsed": {
"info": {
"destination": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"lamports": 962563,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": null
}
],
"recentBlockhash": "cqZ8vtKbuAVtwCRHrATJn7X3kohsJH2Qn9zdhEr8sE5"
},
"signatures": [
"33LHUzKfhBvU68kYib22oFx2XdQKQZ2sfvTmmdCFEr6YidyP8S3WwAurjz6Suewvr2WUByV79K3stNCZDe7wq3De"
]
}
Instruction for program: ComputeBudget111111111111111111111111111111
Data: 3JwEwun4YUPH
Instruction for program: ComputeBudget111111111111111111111111111111
Data: LEJDE7
Instruction: buy
Decoded data: {'amount': 605426095720}
Accounts:
global: 4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf
feeRecipient: CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM
mint: HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump
bondingCurve: 6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn
associatedBondingCurve: 9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd
associatedUser: DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S
user: 2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef
systemProgram: 11111111111111111111111111111111
tokenProgram: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
rent: SysvarRent111111111111111111111111111111111
eventAuthority: Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1
program: 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
Instruction: buy
Decoded data: {'amount': 605426095720}
Accounts:
global: 4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf
feeRecipient: CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM
mint: HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump
bondingCurve: 6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn
associatedBondingCurve: 9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd
associatedUser: DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S
user: 2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef
systemProgram: 11111111111111111111111111111111
tokenProgram: ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL
rent: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
eventAuthority: Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1
program: 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
Parsed instruction: system - transfer
Info: {
"destination": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"lamports": 962563,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
}
Transaction Information:
Blockhash: cqZ8vtKbuAVtwCRHrATJn7X3kohsJH2Qn9zdhEr8sE5
Fee payer: 2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef
Signature: 33LHUzKfhBvU68kYib22oFx2XdQKQZ2sfvTmmdCFEr6YidyP8S3WwAurjz6Suewvr2WUByV79K3stNCZDe7wq3De
@@ -0,0 +1,263 @@
{
"message": {
"accountKeys": [
{
"pubkey": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "SysvarRent111111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"signer": false,
"source": "transaction",
"writable": false
}
],
"addressTableLookups": [],
"instructions": [
{
"accounts": [],
"data": "HnkkG7",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"parsed": {
"info": {
"destination": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"lamports": 4000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [],
"data": "3ZfX8LdfViHV",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "U5L9Srg16xJSo5n5mGEnUQaep1FgNe24zh1oYXVbcVpSyAPk5QWVT8RNVbaJeebkjgPqHUHnWwPyPFmJ21HDBYXgTd8HTU7QfbiY7cn26rn4zxi724rGkbWKwnJHghce74jdF8dLeGwvYnU",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"wallet": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "create"
},
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "AJTQ2h9DXrBiKPvzMVAo11jUarcFAxcz3",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
}
],
"recentBlockhash": "4LkonCgzoF4HF4ZmrczNCntkk5QJzoBfwEG67o99S6yR"
},
"signatures": [
"52ar89rghM8EwKZkxFnBMC4LaMReqtVdpxqXxGWBCMYV1DnYdLrdsqJo8Hbn9KjVpckAokqGNHzTSVfK5xuLepdC",
"SpE85aiJConP43xzaqrri6TRmEbKZdiSJoXeTixJPuMkYUSQZbyjxrb3NbatshfoggYacnyd1YWJf98iPV5YYqm"
]
}
Instruction for program: ComputeBudget111111111111111111111111111111
Data: HnkkG7
Parsed instruction: system - transfer
Info: {
"destination": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"lamports": 4000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
}
Instruction for program: ComputeBudget111111111111111111111111111111
Data: 3ZfX8LdfViHV
Instruction: create
Decoded data: {'name': 'excited', 'symbol': 'excited', 'uri': 'https://cf-ipfs.com/ipfs/QmcDiP9wAZ8QeijrNrtwLeMGk46vKAAe8yvfWtumBZbURq'}
Accounts:
mint: ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp
mintAuthority: TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM
bondingCurve: FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH
associatedBondingCurve: 6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF
global: 4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf
mplTokenMetadata: metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s
metadata: H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj
user: Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5
systemProgram: 11111111111111111111111111111111
tokenProgram: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
associatedTokenProgram: ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL
rent: SysvarRent111111111111111111111111111111111
eventAuthority: Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1
program: 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
Parsed instruction: spl-associated-token-account - create
Info: {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"wallet": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
}
Instruction: buy
Decoded data: {'amount': 37951768488745}
Accounts:
global: 4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf
feeRecipient: CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM
mint: ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp
bondingCurve: FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH
associatedBondingCurve: 6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF
associatedUser: BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1
user: Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5
systemProgram: 11111111111111111111111111111111
tokenProgram: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
rent: SysvarRent111111111111111111111111111111111
eventAuthority: Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1
program: 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
Transaction Information:
Blockhash: 4LkonCgzoF4HF4ZmrczNCntkk5QJzoBfwEG67o99S6yR
Fee payer: Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5
Signature: 52ar89rghM8EwKZkxFnBMC4LaMReqtVdpxqXxGWBCMYV1DnYdLrdsqJo8Hbn9KjVpckAokqGNHzTSVfK5xuLepdC
+67
View File
@@ -0,0 +1,67 @@
import asyncio
import struct
import sys
import os
from typing import Final
from construct import Struct, Int64ul, Flag
from solana.rpc.async_api import AsyncClient
from solders.pubkey import Pubkey
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from config import RPC_ENDPOINT
LAMPORTS_PER_SOL: Final[int] = 1_000_000_000
TOKEN_DECIMALS: Final[int] = 6
CURVE_ADDRESS: Final[str] = "6GXfUqrmPM4VdN1NoDZsE155jzRegJngZRjMkGyby7do"
# Here and later all the discriminators are precalculated. See learning-examples/discriminator.py
EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 6966180631402821399)
class BondingCurveState:
_STRUCT = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag
)
def __init__(self, data: bytes) -> None:
parsed = self._STRUCT.parse(data[8:])
self.__dict__.update(parsed)
async def get_bonding_curve_state(conn: AsyncClient, curve_address: Pubkey) -> BondingCurveState:
response = await conn.get_account_info(curve_address)
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
data = response.value.data
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return BondingCurveState(data)
def calculate_bonding_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (curve_state.virtual_token_reserves / 10 ** TOKEN_DECIMALS)
async def main() -> None:
try:
async with AsyncClient(RPC_ENDPOINT) as conn:
curve_address = Pubkey.from_string(CURVE_ADDRESS)
bonding_curve_state = await get_bonding_curve_state(conn, curve_address)
token_price_sol = calculate_bonding_curve_price(bonding_curve_state)
print("Token price:")
print(f" {token_price_sol:.10f} SOL")
except ValueError as e:
print(f"Error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,109 @@
import asyncio
import json
import websockets
import base64
import struct
import hashlib
import sys
import os
from solders.transaction import VersionedTransaction
from solders.pubkey import Pubkey
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from config import WSS_ENDPOINT, PUMP_PROGRAM
def load_idl(file_path):
with open(file_path, 'r') as f:
return json.load(f)
def decode_create_instruction(ix_data, ix_def, accounts):
args = {}
offset = 8 # Skip 8-byte discriminator
for arg in ix_def['args']:
if arg['type'] == 'string':
length = struct.unpack_from('<I', ix_data, offset)[0]
offset += 4
value = ix_data[offset:offset+length].decode('utf-8')
offset += length
elif arg['type'] == 'publicKey':
value = base64.b64encode(ix_data[offset:offset+32]).decode('utf-8')
offset += 32
else:
raise ValueError(f"Unsupported type: {arg['type']}")
args[arg['name']] = value
# Add accounts
args['mint'] = str(accounts[0])
args['bondingCurve'] = str(accounts[2])
args['associatedBondingCurve'] = str(accounts[3])
args['user'] = str(accounts[7])
return args
# Here and later all the discriminators are precalculated. See learning-examples/discriminator.py
async def listen_and_decode_create():
idl = load_idl('../idl/pump_fun_idl.json')
create_discriminator = 8576854823835016728
async with websockets.connect(WSS_ENDPOINT) as websocket:
subscription_message = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "blockSubscribe",
"params": [
{"mentionsAccountOrProgram": str(PUMP_PROGRAM)},
{
"commitment": "confirmed",
"encoding": "base64",
"showRewards": False,
"transactionDetails": "full",
"maxSupportedTransactionVersion": 0
}
]
})
await websocket.send(subscription_message)
print(f"Subscribed to blocks mentioning program: {PUMP_PROGRAM}")
while True:
try:
response = await websocket.recv()
data = json.loads(response)
if 'method' in data and data['method'] == 'blockNotification':
if 'params' in data and 'result' in data['params']:
block_data = data['params']['result']
if 'value' in block_data and 'block' in block_data['value']:
block = block_data['value']['block']
if 'transactions' in block:
for tx in block['transactions']:
if isinstance(tx, dict) and 'transaction' in tx:
tx_data_decoded = base64.b64decode(tx['transaction'][0])
transaction = VersionedTransaction.from_bytes(tx_data_decoded)
for ix in transaction.message.instructions:
if str(transaction.message.account_keys[ix.program_id_index]) == str(PUMP_PROGRAM):
ix_data = bytes(ix.data)
discriminator = struct.unpack('<Q', ix_data[:8])[0]
if discriminator == create_discriminator:
create_ix = next(instr for instr in idl['instructions'] if instr['name'] == 'create')
account_keys = [str(transaction.message.account_keys[index]) for index in ix.accounts]
decoded_args = decode_create_instruction(ix_data, create_ix, account_keys)
print(json.dumps(decoded_args, indent=2))
print("--------------------")
elif 'result' in data:
print(f"Subscription confirmed")
else:
print(f"Received unexpected message type: {data.get('method', 'Unknown')}")
except Exception as e:
print(f"An error occurred: {str(e)}")
print(f"Error details: {type(e).__name__}")
import traceback
traceback.print_exc()
print("WebSocket connection closed.")
if __name__ == "__main__":
asyncio.run(listen_and_decode_create())
+119
View File
@@ -0,0 +1,119 @@
import asyncio
import json
import websockets
import base58
import base64
import struct
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from config import WSS_ENDPOINT, PUMP_PROGRAM
# Load the IDL JSON file
with open('../idl/pump_fun_idl.json', 'r') as f:
idl = json.load(f)
# Extract the "create" instruction definition
create_instruction = next(instr for instr in idl['instructions'] if instr['name'] == 'create')
def parse_create_instruction(data):
if len(data) < 8:
return None
offset = 8
parsed_data = {}
# Parse fields based on CreateEvent structure
fields = [
('name', 'string'),
('symbol', 'string'),
('uri', 'string'),
('mint', 'publicKey'),
('bondingCurve', 'publicKey'),
('user', 'publicKey'),
]
try:
for field_name, field_type in fields:
if field_type == 'string':
length = struct.unpack('<I', data[offset:offset+4])[0]
offset += 4
value = data[offset:offset+length].decode('utf-8')
offset += length
elif field_type == 'publicKey':
value = base58.b58encode(data[offset:offset+32]).decode('utf-8')
offset += 32
parsed_data[field_name] = value
return parsed_data
except:
return None
def print_transaction_details(log_data):
print(f"Signature: {log_data.get('signature')}")
for log in log_data.get('logs', []):
if log.startswith("Program data:"):
try:
data = base58.b58decode(log.split(": ")[1]).decode('utf-8')
print(f"Data: {data}")
except:
pass
async def listen_for_new_tokens():
while True:
try:
async with websockets.connect(WSS_ENDPOINT) as websocket:
subscription_message = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "logsSubscribe",
"params": [
{"mentions": [str(PUMP_PROGRAM)]},
{"commitment": "processed"}
]
})
await websocket.send(subscription_message)
print(f"Listening for new token creations from program: {PUMP_PROGRAM}")
# Wait for subscription confirmation
response = await websocket.recv()
print(f"Subscription response: {response}")
while True:
try:
response = await websocket.recv()
data = json.loads(response)
if 'method' in data and data['method'] == 'logsNotification':
log_data = data['params']['result']['value']
logs = log_data.get('logs', [])
if any("Program log: Instruction: Create" in log for log in logs):
for log in logs:
if "Program data:" in log:
try:
encoded_data = log.split(": ")[1]
decoded_data = base64.b64decode(encoded_data)
parsed_data = parse_create_instruction(decoded_data)
if parsed_data and 'name' in parsed_data:
print("Signature:", log_data.get('signature'))
for key, value in parsed_data.items():
print(f"{key}: {value}")
print("##########################################################################################")
except Exception as e:
print(f"Failed to decode: {log}")
print(f"Error: {str(e)}")
except Exception as e:
print(f"An error occurred while processing message: {e}")
break
except Exception as e:
print(f"Connection error: {e}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(listen_for_new_tokens())
+68
View File
@@ -0,0 +1,68 @@
import websockets
import asyncio
import json
from datetime import datetime
# PumpPortal WebSocket URL
WS_URL = "wss://pumpportal.fun/api/data"
def format_sol(value):
return f"{value:.6f} SOL"
def format_timestamp(timestamp):
return datetime.fromtimestamp(timestamp / 1000).strftime('%Y-%m-%d %H:%M:%S')
async def listen_for_new_tokens():
async with websockets.connect(WS_URL) as websocket:
# Subscribe to new token events
await websocket.send(json.dumps({
"method": "subscribeNewToken",
"params": []
}))
print("Listening for new token creations...")
while True:
try:
message = await websocket.recv()
data = json.loads(message)
if 'method' in data and data['method'] == 'newToken':
token_info = data.get('params', [{}])[0]
elif 'signature' in data and 'mint' in data:
token_info = data
else:
continue
print("\n" + "=" * 50)
print(f"New token created: {token_info.get('name')} ({token_info.get('symbol')})")
print("=" * 50)
print(f"Address: {token_info.get('mint')}")
print(f"Creator: {token_info.get('traderPublicKey')}")
print(f"Initial Buy: {format_sol(token_info.get('initialBuy', 0))}")
print(f"Market Cap: {format_sol(token_info.get('marketCapSol', 0))}")
print(f"Bonding Curve: {token_info.get('bondingCurveKey')}")
print(f"Virtual SOL: {format_sol(token_info.get('vSolInBondingCurve', 0))}")
print(f"Virtual Tokens: {token_info.get('vTokensInBondingCurve', 0):,.0f}")
print(f"Metadata URI: {token_info.get('uri')}")
print(f"Signature: {token_info.get('signature')}")
print("=" * 50)
except websockets.exceptions.ConnectionClosed:
print("\nWebSocket connection closed. Reconnecting...")
break
except json.JSONDecodeError:
print(f"\nReceived non-JSON message: {message}")
except Exception as e:
print(f"\nAn error occurred: {e}")
async def main():
while True:
try:
await listen_for_new_tokens()
except Exception as e:
print(f"\nAn error occurred: {e}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(main())
+282
View File
@@ -0,0 +1,282 @@
import asyncio
import json
import base64
import struct
import base58
from solana.rpc.async_api import AsyncClient
from solana.transaction import Transaction
from solana.rpc.commitment import Confirmed
from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.instruction import Instruction, AccountMeta
from solana.rpc.types import TxOpts
from solders.system_program import TransferParams, transfer
from spl.token.instructions import get_associated_token_address
import websockets
import hashlib
from solders.transaction import VersionedTransaction
import spl.token.instructions as spl_token
from construct import Struct, Int64ul, Flag
# Here and later all the discriminators are precalculated. See learning-examples/discriminator.py
EXPECTED_DISCRIMINATOR = struct.pack("<Q", 6966180631402821399)
TOKEN_DECIMALS = 6
# Global constants
PUMP_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
PUMP_GLOBAL = Pubkey.from_string("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf")
PUMP_EVENT_AUTHORITY = Pubkey.from_string("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1")
PUMP_FEE = Pubkey.from_string("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM")
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
SYSTEM_RENT = Pubkey.from_string("SysvarRent111111111111111111111111111111111")
SOL = Pubkey.from_string("So11111111111111111111111111111111111111112")
LAMPORTS_PER_SOL = 1_000_000_000
# RPC endpoint
RPC_ENDPOINT = "SOLANA_NODE_RPC_ENDPOINT"
class BondingCurveState:
_STRUCT = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag
)
def __init__(self, data: bytes) -> None:
parsed = self._STRUCT.parse(data[8:])
self.__dict__.update(parsed)
async def get_pump_curve_state(conn: AsyncClient, curve_address: Pubkey) -> BondingCurveState:
response = await conn.get_account_info(curve_address)
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
data = response.value.data
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return BondingCurveState(data)
def calculate_pump_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (curve_state.virtual_token_reserves / 10 ** TOKEN_DECIMALS)
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("SOLANA_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
)
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
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 # Success, exit the function
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.")
RPC_NODE_URL = "SOLANA_NODE_WS_ENDPOINT"
def load_idl(file_path):
with open(file_path, 'r') as f:
return json.load(f)
def calculate_discriminator(instruction_name):
sha = hashlib.sha256()
sha.update(instruction_name.encode('utf-8'))
return struct.unpack('<Q', sha.digest()[:8])[0]
def decode_create_instruction(ix_data, ix_def, accounts):
args = {}
offset = 8 # Skip 8-byte discriminator
for arg in ix_def['args']:
if arg['type'] == 'string':
length = struct.unpack_from('<I', ix_data, offset)[0]
offset += 4
value = ix_data[offset:offset+length].decode('utf-8')
offset += length
elif arg['type'] == 'publicKey':
value = base64.b64encode(ix_data[offset:offset+32]).decode('utf-8')
offset += 32
else:
raise ValueError(f"Unsupported type: {arg['type']}")
args[arg['name']] = value
# Add accounts
args['mint'] = str(accounts[0])
args['bondingCurve'] = str(accounts[2])
args['associatedBondingCurve'] = str(accounts[3])
args['user'] = str(accounts[7])
return args
async def listen_for_create_transaction():
idl = load_idl('../idl/pump_fun_idl.json')
create_discriminator = calculate_discriminator("global:create")
async with websockets.connect(RPC_NODE_URL) as websocket:
subscription_message = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "blockSubscribe",
"params": [
{"mentionsAccountOrProgram": str(PUMP_PROGRAM)},
{
"commitment": "confirmed",
"encoding": "base64",
"showRewards": False,
"transactionDetails": "full",
"maxSupportedTransactionVersion": 0
}
]
})
await websocket.send(subscription_message)
print(f"Subscribed to blocks mentioning program: {PUMP_PROGRAM}")
while True:
response = await websocket.recv()
data = json.loads(response)
if 'method' in data and data['method'] == 'blockNotification':
if 'params' in data and 'result' in data['params']:
block_data = data['params']['result']
if 'value' in block_data and 'block' in block_data['value']:
block = block_data['value']['block']
if 'transactions' in block:
for tx in block['transactions']:
if isinstance(tx, dict) and 'transaction' in tx:
tx_data_decoded = base64.b64decode(tx['transaction'][0])
transaction = VersionedTransaction.from_bytes(tx_data_decoded)
for ix in transaction.message.instructions:
if str(transaction.message.account_keys[ix.program_id_index]) == str(PUMP_PROGRAM):
ix_data = bytes(ix.data)
discriminator = struct.unpack('<Q', ix_data[:8])[0]
if discriminator == create_discriminator:
create_ix = next(instr for instr in idl['instructions'] if instr['name'] == 'create')
account_keys = [str(transaction.message.account_keys[index]) for index in ix.accounts]
decoded_args = decode_create_instruction(ix_data, create_ix, account_keys)
return decoded_args
async def main():
print("Waiting for a new token creation...")
token_data = await listen_for_create_transaction()
print("New token created:")
print(json.dumps(token_data, indent=2))
print("Waiting for 15 seconds for things to stabilize...")
await asyncio.sleep(15)
mint = Pubkey.from_string(token_data['mint'])
bonding_curve = Pubkey.from_string(token_data['bondingCurve'])
associated_bonding_curve = Pubkey.from_string(token_data['associatedBondingCurve'])
# Fetch the token price
async with AsyncClient(RPC_ENDPOINT) as client:
curve_state = await get_pump_curve_state(client, bonding_curve)
token_price_sol = calculate_pump_curve_price(curve_state)
# Amount of SOL to spend (adjust as needed)
amount = 0.00001 # 0.00001 SOL
slippage = 0.3 # 30% slippage tolerance
print(f"Bonding curve address: {bonding_curve}")
print(f"Token price: {token_price_sol:.10f} SOL")
print(f"Buying {amount:.6f} SOL worth of the new token with {slippage*100:.1f}% slippage tolerance...")
await buy_token(mint, bonding_curve, associated_bonding_curve, amount, slippage)
if __name__ == "__main__":
asyncio.run(main())
+166
View File
@@ -0,0 +1,166 @@
import asyncio
import json
import base64
import struct
import base58
from solana.rpc.async_api import AsyncClient
from solana.transaction import Transaction
from solana.rpc.commitment import Confirmed
from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.instruction import Instruction, AccountMeta
from solana.rpc.types import TxOpts
from solders.system_program import TransferParams, transfer
from spl.token.instructions import get_associated_token_address
import spl.token.instructions as spl_token
from construct import Struct, Int64ul, Flag
# Here and later all the discriminators are precalculated. See learning-examples/discriminator.py
EXPECTED_DISCRIMINATOR = struct.pack("<Q", 6966180631402821399)
TOKEN_DECIMALS = 6
# Global constants
PUMP_PROGRAM = Pubkey.from_string("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
PUMP_GLOBAL = Pubkey.from_string("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf")
PUMP_EVENT_AUTHORITY = Pubkey.from_string("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1")
PUMP_FEE = Pubkey.from_string("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM")
SYSTEM_PROGRAM = Pubkey.from_string("11111111111111111111111111111111")
SYSTEM_TOKEN_PROGRAM = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
SYSTEM_RENT = Pubkey.from_string("SysvarRent111111111111111111111111111111111")
SOL = Pubkey.from_string("So11111111111111111111111111111111111111112")
LAMPORTS_PER_SOL = 1_000_000_000
UNIT_PRICE = 10_000_000
UNIT_BUDGET = 100_000
# RPC endpoint
RPC_ENDPOINT = "SOLANA_NODE_RPC_ENDPOINT"
class BondingCurveState:
_STRUCT = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag
)
def __init__(self, data: bytes) -> None:
parsed = self._STRUCT.parse(data[8:])
self.__dict__.update(parsed)
async def get_pump_curve_state(conn: AsyncClient, curve_address: Pubkey) -> BondingCurveState:
response = await conn.get_account_info(curve_address)
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
data = response.value.data
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return BondingCurveState(data)
def calculate_pump_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (curve_state.virtual_token_reserves / 10 ** TOKEN_DECIMALS)
async def get_token_balance(conn: AsyncClient, associated_token_account: Pubkey):
response = await conn.get_token_account_balance(associated_token_account)
if response.value:
return int(response.value.amount)
return 0
async def sell_token(mint: Pubkey, bonding_curve: Pubkey, associated_bonding_curve: Pubkey, slippage: float = 0.25, max_retries=5):
private_key = base58.b58decode("SOLANA_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)
# Get token balance
token_balance = await get_token_balance(client, associated_token_account)
token_balance_decimal = token_balance / 10**TOKEN_DECIMALS
print(f"Token balance: {token_balance_decimal}")
if token_balance == 0:
print("No tokens to sell.")
return
# Fetch the token price
curve_state = await get_pump_curve_state(client, bonding_curve)
token_price_sol = calculate_pump_curve_price(curve_state)
print(f"Price per Token: {token_price_sol:.20f} SOL")
# Calculate minimum SOL output
amount = token_balance
min_sol_output = float(token_balance_decimal) * float(token_price_sol)
slippage_factor = 1 - slippage
min_sol_output = int((min_sol_output * slippage_factor) * LAMPORTS_PER_SOL)
print(f"Selling {token_balance_decimal} tokens")
print(f"Minimum SOL output: {min_sol_output / LAMPORTS_PER_SOL:.10f} SOL")
# Continue with the sell 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_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, 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", 12502976635542562355)
data = discriminator + struct.pack("<Q", amount) + struct.pack("<Q", min_sol_output)
sell_ix = Instruction(PUMP_PROGRAM, data, accounts)
recent_blockhash = await client.get_latest_blockhash()
transaction = Transaction()
transaction.add(sell_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 # Success, exit the function
except Exception as e:
print(f"Attempt {attempt + 1} failed: {str(e)}")
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
print(f"Retrying in {wait_time} seconds...")
await asyncio.sleep(wait_time)
else:
print("Max retries reached. Unable to complete the transaction.")
async def main():
# Replace these with the actual values for the token you want to sell
mint = Pubkey.from_string("EyLuyWV5N1GVSqLLeumFDWYkmmSkLED5s2xqu37Lpump")
bonding_curve = Pubkey.from_string("AGZLYVwmGL9cXCLN4C3ki9hXGix1kXYjr59B2H7jwRMQ")
associated_bonding_curve = Pubkey.from_string("74H2bo2hjNnWgf9oDHzsVsu3mcsoiYYWJ3s9dVnL5erV")
slippage = 0.25 # 25% slippage tolerance
print(f"Bonding curve address: {bonding_curve}")
print(f"Selling tokens with {slippage*100:.1f}% slippage tolerance...")
await sell_token(mint, bonding_curve, associated_bonding_curve, slippage)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"1.18.22","slot":285247740},"value":{"data":["F7f4N2DYrGD99rN6is0DALwvcwAHAAAA/V6hLvnOAgC8g08EAAAAAACAxqR+jQMAAA==","base64"],"executable":false,"lamports":73551852,"owner":"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P","rentEpoch":18446744073709551615,"space":49}},"id":1}
@@ -0,0 +1,388 @@
{
"jsonrpc": "2.0",
"result": {
"blockTime": 1724126293,
"meta": {
"computeUnitsConsumed": 68322,
"err": null,
"fee": 32000,
"innerInstructions": [
{
"index": 2,
"instructions": [
{
"parsed": {
"info": {
"amount": "605426095720",
"authority": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"destination": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"source": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd"
},
"type": "transfer"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"lamports": 24080282,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"lamports": 240802,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "2K7nL28PxCW8ejnyCeuMpbYBaHNNxSWmhNFbMDYBXdWw7nSYrc7woNd4ENfAZMMQjP9TLFxfRvA69i3wPHorNMpqcfCFFFFeAmfcVqdtaPqq3JE1erMrE8gHpGJ8NXA1633JV4iabs9saqZ8Pa7xQrjkoYX8pgbAjh3CnePG1Lq18E9fsPv89nKqmgvb",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
},
{
"index": 3,
"instructions": [
{
"parsed": {
"info": {
"amount": "605426095720",
"authority": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"destination": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"source": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S"
},
"type": "transfer"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "2K7nL28PxCW8ejnyCeuMpbYBaHNNxSWmhNFbMDYBXdWw7nSYrc7woNd4ENfAZMMQjP9RGosGgCYezUhV4mEBVCtoTrbAXXkFVvp72dtBLa7fuvzRsmCgMkydN6Ez8H17gRiXkmmNHUCXcUmfhMG2cGeaukQWu1YD7mkmTzg7QGUF69ArSTS3RHHM6zXh",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Buy",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 129562 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 117474 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe73itfzw580Z6SEg9q3HfHO2n0qXIpNVTcl7oo9jo+CP5pvbwEAAAAAaBY19owAAAABHKbz9pJ3+YMsz+xMr0BHBMU3VB0RDjRv3ae0eInXRhRVFMRmAAAAAFjTeFUIAAAAbRsnNO0xAwBYJ1VZAQAAAG2DFOhbMwIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 35954 of 149700 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Sell",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 93687 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 85557 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe73itfzw580Z6SEg9q3HfHO2n0qXIpNVTcl7oo9jo+CP5lvbwEAAAAAaBY19owAAAAAHKbz9pJ3+YMsz+xMr0BHBMU3VB0RDjRv3ae0eInXRhRVFMRmAAAAAL9jCVQIAAAA1TFcKnoyAwC/t+VXAQAAANWZSd7oMwIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 31918 of 113746 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success"
],
"postBalances": [
706655008,
5770871791,
2039280,
279629252504426,
2039280,
97135324113,
1,
1141440,
1,
1009200,
934087680,
2500000,
731913600,
0,
1461600
],
"postTokenBalances": [
{
"accountIndex": 2,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "826925208216021",
"decimals": 6,
"uiAmount": 826925208.216021,
"uiAmountString": "826925208.216021"
}
},
{
"accountIndex": 4,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "0",
"decimals": 6,
"uiAmount": null,
"uiAmountString": "0"
}
}
],
"preBalances": [
708131176,
5770871790,
2039280,
279629252022822,
2039280,
97134361550,
1,
1141440,
1,
1009200,
934087680,
2500000,
731913600,
0,
1461600
],
"preTokenBalances": [
{
"accountIndex": 2,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "826925208216021",
"decimals": 6,
"uiAmount": 826925208.216021,
"uiAmountString": "826925208.216021"
}
},
{
"accountIndex": 4,
"mint": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"owner": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "0",
"decimals": 6,
"uiAmount": null,
"uiAmountString": "0"
}
}
],
"rewards": [],
"status": {
"Ok": null
}
},
"slot": 284677332,
"transaction": {
"message": {
"accountKeys": [
{
"pubkey": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "SysvarRent111111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"signer": false,
"source": "transaction",
"writable": false
}
],
"addressTableLookups": [],
"instructions": [
{
"accounts": [],
"data": "3JwEwun4YUPH",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [],
"data": "LEJDE7",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "AJTQ2h9DXrBqzdpEhcLVYocNoqujioBxb",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"HfJVjBdkhAD2ynVM8PdTSii4ECZdsxNTCx5wpEqUpump",
"6fogeBTRjgm9Kb9dVtqpjDf6bGvjGgdScmTu5nCVPJPn",
"9nj8QEp6mQDsr2G6oGtq8DJakPuKLeUqnWMf4JzgcSCd",
"DxMF77MqYYYr4NshXWrUdiGzfzwpNhKG7H73B94ETX8S",
"2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef",
"11111111111111111111111111111111",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "5jRcjdixRUDSvSh4QXANSHU9rk2He2WMm",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"parsed": {
"info": {
"destination": "JBfdxsh3DEXfpeTUrQe94hpKQ8yxBqVRqRiSRvemUA4i",
"lamports": 962563,
"source": "2vr538qDgHCPYmr2mjt5LSjQ3kBYjtw3SDSveUKBVkef"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": null
}
],
"recentBlockhash": "cqZ8vtKbuAVtwCRHrATJn7X3kohsJH2Qn9zdhEr8sE5"
},
"signatures": [
"33LHUzKfhBvU68kYib22oFx2XdQKQZ2sfvTmmdCFEr6YidyP8S3WwAurjz6Suewvr2WUByV79K3stNCZDe7wq3De"
]
},
"version": 0
},
"id": 1
}
@@ -0,0 +1,706 @@
{
"jsonrpc": "2.0",
"result": {
"blockTime": 1724128600,
"meta": {
"computeUnitsConsumed": 179064,
"err": null,
"fee": 88750,
"innerInstructions": [
{
"index": 3,
"instructions": [
{
"parsed": {
"info": {
"lamports": 1461600,
"newAccount": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 82
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"decimals": 6,
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "initializeMint2"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"lamports": 1231920,
"newAccount": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"owner": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 49
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"wallet": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH"
},
"type": "create"
},
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"stackHeight": 2
},
{
"parsed": {
"info": {
"extensionTypes": [
"immutableOwner"
],
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp"
},
"type": "getAccountDataSize"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 3
},
{
"parsed": {
"info": {
"lamports": 2039280,
"newAccount": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 165
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF"
},
"type": "initializeImmutableOwner"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH"
},
"type": "initializeAccount3"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 3
},
{
"accounts": [
"H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"11111111111111111111111111111111"
],
"data": "e5DmuZMrE66La6keggPtmZttXAHyPqrUdsWHGdAwjTu9Zi4QvU6WzPSyxrXtdgYkxfoP9G7ETiVjf1oBwq2u8NmkRUqrtiw4R1Hx6mNAPVHXxtGrCDcVg4AwcJ3hqcdndudCkB4b9GkJjFu",
"programId": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"lamports": 15616720,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"space": 679
},
"type": "allocate"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
},
"type": "assign"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 3
},
{
"parsed": {
"info": {
"account": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"amount": "1000000000000000",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"mintAuthority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"
},
"type": "mintTo"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"authority": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"authorityType": "mintTokens",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"newAuthority": null
},
"type": "setAuthority"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "5xcpNtotVBphT5Ckdf46pY6eeCiYbvrziarwLuSnoKaMkWNb2cZaD9feuADHprV4j7wcAP8E6tEGJk43TyUVXuCUjnP5YXBquQK7TCHwvqjiY1TM8sdvHQW9ciLj25dQuQC7JZ3Pgr832WvmExjr8F9mypGDRTavTfrBcfeUQzg4bTeYcGeTDCyEWFPgmGeT37grRSKj6PK5jP6JiW2q4gCEbgGxiLCfML9Qy2iovLEJ6uXwxLrTyiZ4x3G7eFLHkzjKN6CLRquMqD123t22UxZBhugGRT",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
},
{
"index": 4,
"instructions": [
{
"parsed": {
"info": {
"extensionTypes": [
"immutableOwner"
],
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp"
},
"type": "getAccountDataSize"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"lamports": 2039280,
"newAccount": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"space": 165
},
"type": "createAccount"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1"
},
"type": "initializeImmutableOwner"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "initializeAccount3"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
}
]
},
{
"index": 5,
"instructions": [
{
"parsed": {
"info": {
"amount": "37951768488745",
"authority": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"destination": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"source": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF"
},
"type": "transfer"
},
"program": "spl-token",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"lamports": 1100000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"parsed": {
"info": {
"destination": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"lamports": 11000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": 2
},
{
"accounts": [
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"
],
"data": "2K7nL28PxCW8ejnyCeuMpbXg4p3TxoCZETw2SodjK89Y1dHFkcjQaBAgMqnf4KDfhbC4774odcRcjDbB7G7xsGx95mVCrqiNQcX59kbAV5fx2XHu3WoCTiu9yyVbtyyuHqHPZuL18cevQMPTtggdQtDyzfxLKCEt4FnTfX2oRD7csmk3vFncJgCDcBQB",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": 2
}
]
}
],
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Create",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeMint2",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2780 of 237974 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1595 of 214078 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 207465 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4214 of 203581 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 21990 of 221053 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [2]",
"Program log: IX: Create Metadata Accounts v3",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Allocate space for the account",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program log: Assign the account to the owning program",
"Program 11111111111111111111111111111111 invoke [3]",
"Program 11111111111111111111111111111111 success",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s consumed 36258 of 183748 compute units",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: MintTo",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4492 of 144975 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: SetAuthority",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2911 of 138336 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 131120 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: G3KpTd7rY3YHAAAAZXhjaXRlZAcAAABleGNpdGVkRwAAAGh0dHBzOi8vY2YtaXBmcy5jb20vaXBmcy9RbWNEaVA5d0FaOFFlaWpyTnJ0d0xlTUdrNDZ2S0FBZTh5dmZXdHVtQlpiVVJxx09pPxZatyeZoNyW2ve9tDfrT5dl7bJ0JjqTw0Orr0/T20gu0JUEOdSfmHbuZqF6sdH2JuMaAwa4lWuHXNGtQN0QsFdumei71UE0T9w/IatQ85pk4JEI1dEkqI1gmS5+",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 122356 of 249550 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
"Program log: Create",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: GetAccountDataSize",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 121831 compute units",
"Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program log: Initialize the associated token account",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeImmutableOwner",
"Program log: Please upgrade to SPL Token 2022 for immutable owner support",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 115244 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: InitializeAccount3",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 111364 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20301 of 127194 compute units",
"Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [1]",
"Program log: Instruction: Buy",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
"Program log: Instruction: Transfer",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 86752 compute units",
"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 11111111111111111111111111111111 invoke [2]",
"Program 11111111111111111111111111111111 success",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 74664 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success",
"Program data: vdt/007mYe7HT2k/Flq3J5mg3Jba9720N+tPl2XtsnQmOpPDQ6uvTwCrkEEAAAAAKeutVYQiAAAB3RCwV26Z6LvVQTRP3D8hq1DzmmTgkQjV0SSojWCZLn5YHcRmAAAAAABXtD0HAAAA1yQq8l6tAwAAq5BBAAAAANeMF6bNrgIA",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 35957 of 106893 compute units",
"Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"
],
"postBalances": [
122171125343,
1461600,
733959725969,
1101231920,
2039280,
15616720,
2039280,
279706994391733,
1,
1,
1141440,
323296939,
2500000,
1141440,
934087680,
731913600,
1009200,
0
],
"postTokenBalances": [
{
"accountIndex": 4,
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "962048231511255",
"decimals": 6,
"uiAmount": 962048231.511255,
"uiAmountString": "962048231.511255"
}
},
{
"accountIndex": 6,
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"owner": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "37951768488745",
"decimals": 6,
"uiAmount": 37951768.488745,
"uiAmountString": "37951768.488745"
}
}
],
"preBalances": [
123308602893,
0,
733955725969,
0,
0,
0,
0,
279706983391733,
1,
1,
1141440,
323296939,
2500000,
1141440,
934087680,
731913600,
1009200,
0
],
"preTokenBalances": [],
"rewards": [],
"status": {
"Ok": null
}
},
"slot": 284682639,
"transaction": {
"message": {
"accountKeys": [
{
"pubkey": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "ComputeBudget111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "SysvarRent111111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"signer": false,
"source": "transaction",
"writable": false
}
],
"addressTableLookups": [],
"instructions": [
{
"accounts": [],
"data": "HnkkG7",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"parsed": {
"info": {
"destination": "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY",
"lamports": 4000000,
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [],
"data": "3ZfX8LdfViHV",
"programId": "ComputeBudget111111111111111111111111111111",
"stackHeight": null
},
{
"accounts": [
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM",
"FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
"H6LkmMUuAiJhAcH9ejScvMVXFhUSzxwYPiczL7zW3aAj",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "U5L9Srg16xJSo5n5mGEnUQaep1FgNe24zh1oYXVbcVpSyAPk5QWVT8RNVbaJeebkjgPqHUHnWwPyPFmJ21HDBYXgTd8HTU7QfbiY7cn26rn4zxi724rGkbWKwnJHghce74jdF8dLeGwvYnU",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
},
{
"parsed": {
"info": {
"account": "BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"mint": "ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"source": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"systemProgram": "11111111111111111111111111111111",
"tokenProgram": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"wallet": "Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5"
},
"type": "create"
},
"program": "spl-associated-token-account",
"programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"stackHeight": null
},
{
"accounts": [
"4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf",
"CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
"ER2N5eaDoC68kNhj7LyaScimzq7deaqxiw88rewvxaKp",
"FFzxakVNzpirwMFtLyD22UZ6UM3KLF2EAGC2RxNPaYoH",
"6eTEMemDi58KJE1rPEagqMsgn34xUWTkzdZTKM8EVbYF",
"BfUATFeQBKLdaTGdCT9bKkxXrYTYaRkcjtQ4iFwMGVq1",
"Fswrw3tgQL597kCexxLEhft6a7Su4CDoqwRMqqj4BEp5",
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"SysvarRent111111111111111111111111111111111",
"Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
"data": "AJTQ2h9DXrBiKPvzMVAo11jUarcFAxcz3",
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"stackHeight": null
}
],
"recentBlockhash": "4LkonCgzoF4HF4ZmrczNCntkk5QJzoBfwEG67o99S6yR"
},
"signatures": [
"52ar89rghM8EwKZkxFnBMC4LaMReqtVdpxqXxGWBCMYV1DnYdLrdsqJo8Hbn9KjVpckAokqGNHzTSVfK5xuLepdC",
"SpE85aiJConP43xzaqrri6TRmEbKZdiSJoXeTixJPuMkYUSQZbyjxrb3NbatshfoggYacnyd1YWJf98iPV5YYqm"
]
},
"version": 0
},
"id": 1
}
+141
View File
@@ -0,0 +1,141 @@
import asyncio
import json
import base64
import struct
import base58
from typing import Final
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 spl.token.instructions import get_associated_token_address
import spl.token.instructions as spl_token
from construct import Struct, Int64ul, Flag
from config import *
# Here and later all the discriminators are precalculated. See learning-examples/discriminator.py
EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 6966180631402821399)
TOKEN_DECIMALS: Final[int] = 6
class BondingCurveState:
_STRUCT = Struct(
"virtual_token_reserves" / Int64ul,
"virtual_sol_reserves" / Int64ul,
"real_token_reserves" / Int64ul,
"real_sol_reserves" / Int64ul,
"token_total_supply" / Int64ul,
"complete" / Flag
)
def __init__(self, data: bytes) -> None:
parsed = self._STRUCT.parse(data[8:])
self.__dict__.update(parsed)
async def get_pump_curve_state(conn: AsyncClient, curve_address: Pubkey) -> BondingCurveState:
response = await conn.get_account_info(curve_address)
if not response.value or not response.value.data:
raise ValueError("Invalid curve state: No data")
data = response.value.data
if data[:8] != EXPECTED_DISCRIMINATOR:
raise ValueError("Invalid curve state discriminator")
return BondingCurveState(data)
def calculate_pump_curve_price(curve_state: BondingCurveState) -> float:
if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0:
raise ValueError("Invalid reserve state")
return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / (curve_state.virtual_token_reserves / 10 ** TOKEN_DECIMALS)
async def get_token_balance(conn: AsyncClient, associated_token_account: Pubkey):
response = await conn.get_token_account_balance(associated_token_account)
if response.value:
return int(response.value.amount)
return 0
async def sell_token(mint: Pubkey, bonding_curve: Pubkey, associated_bonding_curve: Pubkey, slippage: float = 0.25, 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)
# Get token balance
token_balance = await get_token_balance(client, associated_token_account)
token_balance_decimal = token_balance / 10**TOKEN_DECIMALS
print(f"Token balance: {token_balance_decimal}")
if token_balance == 0:
print("No tokens to sell.")
return
# Fetch the token price
curve_state = await get_pump_curve_state(client, bonding_curve)
token_price_sol = calculate_pump_curve_price(curve_state)
print(f"Price per Token: {token_price_sol:.20f} SOL")
# Calculate minimum SOL output
amount = token_balance
min_sol_output = float(token_balance_decimal) * float(token_price_sol)
slippage_factor = 1 - slippage
min_sol_output = int((min_sol_output * slippage_factor) * LAMPORTS_PER_SOL)
print(f"Selling {token_balance_decimal} tokens")
print(f"Minimum SOL output: {min_sol_output / LAMPORTS_PER_SOL:.10f} SOL")
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_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, 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", 12502976635542562355)
data = discriminator + struct.pack("<Q", amount) + struct.pack("<Q", min_sol_output)
sell_ix = Instruction(PUMP_PROGRAM, data, accounts)
recent_blockhash = await client.get_latest_blockhash()
transaction = Transaction()
transaction.add(sell_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.")
+157
View File
@@ -0,0 +1,157 @@
import asyncio
import json
import base64
import struct
import base58
import hashlib
import websockets
import os
import argparse
from datetime import datetime
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 *
# Import functions from buy.py
from buy import get_pump_curve_state, calculate_pump_curve_price, buy_token, listen_for_create_transaction
# Import functions from sell.py
from sell import sell_token
def log_trade(action, token_data, price, tx_hash):
os.makedirs("trades", exist_ok=True)
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"action": action,
"token_address": token_data['mint'],
"price": price,
"tx_hash": tx_hash
}
with open("trades/trades.log", 'a') as log_file:
json.dump(log_entry, log_file)
log_file.write("\n")
async def trade(websocket=None, match_string=None, bro_address=None, marry_mode=False, yolo_mode=False):
if websocket is None:
async with websockets.connect(WSS_ENDPOINT) as websocket:
await _trade(websocket, match_string, bro_address, marry_mode, yolo_mode)
else:
await _trade(websocket, match_string, bro_address, marry_mode, yolo_mode)
async def _trade(websocket, match_string=None, bro_address=None, marry_mode=False, yolo_mode=False):
while True:
print("Waiting for a new token creation...")
token_data = await listen_for_create_transaction(websocket)
print("New token created:")
print(json.dumps(token_data, indent=2))
if match_string and not (match_string.lower() in token_data['name'].lower() or match_string.lower() in token_data['symbol'].lower()):
print(f"Token does not match the criteria '{match_string}'. Skipping...")
if not yolo_mode:
break
continue
if bro_address and token_data['user'] != bro_address:
print(f"Token not created by the specified user '{bro_address}'. Skipping...")
if not yolo_mode:
break
continue
# Save token information to a .txt file in the "trades" directory
mint_address = token_data['mint']
os.makedirs("trades", exist_ok=True)
file_name = os.path.join("trades", f"{mint_address}.txt")
with open(file_name, 'w') as file:
file.write(json.dumps(token_data, indent=2))
print(f"Token information saved to {file_name}")
print("Waiting for 15 seconds for things to stabilize...")
await asyncio.sleep(15)
mint = Pubkey.from_string(token_data['mint'])
bonding_curve = Pubkey.from_string(token_data['bondingCurve'])
associated_bonding_curve = Pubkey.from_string(token_data['associatedBondingCurve'])
# Fetch the token price
async with AsyncClient(RPC_ENDPOINT) as client:
curve_state = await get_pump_curve_state(client, bonding_curve)
token_price_sol = calculate_pump_curve_price(curve_state)
print(f"Bonding curve address: {bonding_curve}")
print(f"Token price: {token_price_sol:.10f} SOL")
print(f"Buying {BUY_AMOUNT:.6f} SOL worth of the new token with {BUY_SLIPPAGE*100:.1f}% slippage tolerance...")
buy_tx_hash = await buy_token(mint, bonding_curve, associated_bonding_curve, BUY_AMOUNT, BUY_SLIPPAGE)
if buy_tx_hash:
log_trade("buy", token_data, token_price_sol, str(buy_tx_hash))
else:
print("Buy transaction failed.")
if not marry_mode:
print("Waiting for 20 seconds before selling...")
await asyncio.sleep(20)
print(f"Selling tokens with {SELL_SLIPPAGE*100:.1f}% slippage tolerance...")
sell_tx_hash = await sell_token(mint, bonding_curve, associated_bonding_curve, SELL_SLIPPAGE)
if sell_tx_hash:
log_trade("sell", token_data, token_price_sol, str(sell_tx_hash))
else:
print("Sell transaction failed or no tokens to sell.")
else:
print("Marry mode enabled. Skipping sell operation.")
if not yolo_mode:
break
async def main(yolo_mode=False, match_string=None, bro_address=None, marry_mode=False):
if yolo_mode:
while True:
try:
async with websockets.connect(WSS_ENDPOINT) as websocket:
while True:
try:
await trade(websocket, match_string, bro_address, marry_mode, yolo_mode)
except websockets.exceptions.ConnectionClosed:
print("WebSocket connection closed. Reconnecting...")
break
except Exception as e:
print(f"An error occurred: {e}")
print("Waiting for 5 seconds before looking for the next token...")
await asyncio.sleep(5)
except Exception as e:
print(f"Connection error: {e}")
print("Reconnecting in 5 seconds...")
await asyncio.sleep(5)
else:
# For non-YOLO mode, create a websocket connection and close it after one trade
async with websockets.connect(WSS_ENDPOINT) as websocket:
await trade(websocket, match_string, bro_address, marry_mode, yolo_mode)
async def ping_websocket(websocket):
while True:
try:
await websocket.ping()
await asyncio.sleep(20) # Send a ping every 20 seconds
except:
break
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Trade tokens on Solana.")
parser.add_argument("--yolo", action="store_true", help="Run in YOLO mode (continuous trading)")
parser.add_argument("--match", type=str, help="Only trade tokens with names or symbols matching this string")
parser.add_argument("--bro", type=str, help="Only trade tokens created by this user address")
parser.add_argument("--marry", action="store_true", help="Only buy tokens, skip selling")
args = parser.parse_args()
asyncio.run(main(yolo_mode=args.yolo, match_string=args.match, bro_address=args.bro, marry_mode=args.marry))
@@ -0,0 +1,9 @@
{
"name": "RAKAMAKAFO",
"symbol": "MAKAFO",
"uri": "https://cf-ipfs.com/ipfs/QmYyNfffJL8aLzsQQBxSDEmbQ2STSPS35rfFwE7isjJiVu",
"mint": "LR7TYDeWamU7MsCXFH7ydwJYaZfRJs8pzgCQrh2pump",
"bondingCurve": "9UznPeXvYtPqq8saSyM65cC8LCtyAKPnLCGG7Mq1pUTq",
"associatedBondingCurve": "CTe6pwwgzEUvRmPGRE2EZXrESpiWawK5TwyJhgvFgJ6T",
"user": "Ev5WEEJ2Y1qKGE8KCNvBNVEgy9fJUuttA93pMo2fcGFd"
}
+2
View File
@@ -0,0 +1,2 @@
{"timestamp": "2024-08-22T10:51:30.306580", "action": "buy", "token_address": "LR7TYDeWamU7MsCXFH7ydwJYaZfRJs8pzgCQrh2pump", "price": 1.668947042812354e-07, "tx_hash": "XZDRuEnaBNEeuFAiGyJsqBmVF3uZvFqAQUKsZVKTxsThHxN43LiRqy3T4cSH4dRXGB7c5A4855iYQDLY4BNJJhP"}
{"timestamp": "2024-08-22T10:51:56.116951", "action": "sell", "token_address": "LR7TYDeWamU7MsCXFH7ydwJYaZfRJs8pzgCQrh2pump", "price": 1.668947042812354e-07, "tx_hash": "WQHnEoyztfDf5FJyQRXDGxxtqf2EcMGs8SET43KuYU8Dpdunruku22SHnfiH2xsUi1hTBjC1msvTcnU78fFKrc2"}