mirror of
https://github.com/chainstacklabs/pumpfun-bonkfun-bot.git
synced 2026-11-02 06:16:10 +00:00
87 lines
2.9 KiB
Python
87 lines
2.9 KiB
Python
"""Tell whether a transaction succeeded, reverted, or is not visible yet.
|
|
|
|
Usage:
|
|
uv run cookbook/solana/solana_check_transaction.py <SIGNATURE>
|
|
|
|
"Confirmed" and "succeeded" are different questions. `confirmTransaction` answers
|
|
only the first: the signature landed in a block. A landed transaction can still
|
|
have reverted, and RPC says so only in `meta.err`, so a script that stops at
|
|
confirmation prints "success" while the wallet balance never moves.
|
|
|
|
This prints all three states separately:
|
|
|
|
SUCCESS landed, meta.err is null
|
|
REVERTED landed, meta.err is set — the fee was paid, nothing else happened
|
|
UNCONFIRMED the node cannot see it (yet, or ever)
|
|
|
|
A null result is not a failure. On a load-balanced endpoint the node answering
|
|
`getTransaction` is not necessarily the one that confirmed the signature, so a
|
|
good transaction reads back as "not found" for a moment. Treating that as failure
|
|
is how a landed buy gets reported as a failed buy.
|
|
|
|
`max_supported_transaction_version=1` is required: without it the RPC refuses to
|
|
return any transaction in the v1 format.
|
|
"""
|
|
|
|
import argparse
|
|
import asyncio
|
|
import os
|
|
|
|
from dotenv import load_dotenv
|
|
from solana.rpc.async_api import AsyncClient
|
|
from solders.signature import Signature
|
|
|
|
load_dotenv()
|
|
|
|
RPC_ENDPOINT = os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
|
|
|
|
|
|
async def check(signature: Signature) -> None:
|
|
"""Fetch a transaction and print what actually happened to it.
|
|
|
|
Args:
|
|
signature: The transaction signature to inspect
|
|
"""
|
|
async with AsyncClient(RPC_ENDPOINT) as client:
|
|
response = await client.get_transaction(
|
|
signature, commitment="confirmed", max_supported_transaction_version=1
|
|
)
|
|
|
|
if response.value is None:
|
|
print(f"UNCONFIRMED {signature}")
|
|
print("The node has not seen this signature. It may still land.")
|
|
return
|
|
|
|
meta = response.value.transaction.meta
|
|
if meta is None:
|
|
# No metadata means the outcome is unknown, not that it worked.
|
|
print(f"UNCONFIRMED {signature}")
|
|
print("Returned without execution metadata; the outcome is unknown.")
|
|
return
|
|
|
|
if meta.err is not None:
|
|
print(f"REVERTED {signature}")
|
|
print(f"Error: {meta.err}")
|
|
else:
|
|
print(f"SUCCESS {signature}")
|
|
|
|
print(f"Slot: {response.value.slot}")
|
|
print(f"Fee: {meta.fee} lamports")
|
|
if meta.log_messages:
|
|
print("\nProgram logs:")
|
|
for line in meta.log_messages:
|
|
print(f" {line}")
|
|
|
|
|
|
def main() -> None:
|
|
"""Parse the command line and check the signature."""
|
|
parser = argparse.ArgumentParser(description="Check one transaction's outcome")
|
|
parser.add_argument("signature", help="Transaction signature, base58")
|
|
args = parser.parse_args()
|
|
|
|
asyncio.run(check(Signature.from_string(args.signature)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|