如何在Solana上正确解码Jupiter Swap事件?
如何在Solana上正确解码Jupiter Swap事件?
你好!看了你的问题,你现在主要踩了两个关键的坑,导致解析结果完全不对,咱们一步步来修正:
核心问题分析
- 用错了解析数据源:你直接使用了整个交易的原始Hex数据,但Jupiter的Swap事件字节是交易执行后,Jupiter程序输出到日志或事件账户的特定数据段,根本不是整个交易的Data部分。
- 数据类型匹配错误:你用有符号的
Int64ul解析无符号的代币金额(Solana上代币金额都是无符号64位整数u64),虽然小金额不会直接报错,但类型逻辑本身错误,大金额会被解析成负数。
正确的解析流程
第一步:获取正确的Swap事件字节数据
你需要从交易的程序日志里提取Jupiter输出的Swap事件 payload,而不是用整个交易的Hex:
- 用Solscan的话:打开目标交易的「Program Logs」标签,找到Jupiter程序(地址
whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc)的日志,里面会包含事件对应的字节数据。 - 用Solana RPC的话:调用
getTransaction接口,指定encoding="jsonParsed",从返回结果的result.meta.logs字段里提取Jupiter的事件日志。
第二步:手动解析事件数据
Jupiter的Swap事件基于Anchor框架,格式规则是:
- 前8字节:事件判别符(
keccak256("event:Swap")哈希值的前8字节,小端序) - 后续字段依次为:
amm(32字节公钥)、inputMint(32字节公钥)、inputAmount(8字节无符号小端64位整数)、outputMint(32字节公钥)、outputAmount(8字节无符号小端64位整数)
下面是修正后的可运行代码:
from construct import Uint64ul, Bytes, Struct as cStruct import base58 from solana.publickey import PublicKey # 转公钥更省心,也可以直接用base58 # 定义公钥和事件结构 PUBLIC_KEY_LAYOUT = Bytes(32) JUP_SWAP_EVENT = cStruct( "amm" / PUBLIC_KEY_LAYOUT, "inputMint" / PUBLIC_KEY_LAYOUT, "inputAmount" / Uint64ul, # 用无符号Uint64ul对应u64类型 "outputMint" / PUBLIC_KEY_LAYOUT, "outputAmount" / Uint64ul ) # 替换为你从日志中提取的完整事件字节(包含前8字节判别符) full_event_bytes = b"..." # 跳过前8字节的事件判别符,解析有效数据 parsable_data = full_event_bytes[8:] # 解析事件并转换为目标格式 decoded = JUP_SWAP_EVENT.parse(parsable_data) result = { "amm": PublicKey(decoded.amm).__str__(), "inputMint": PublicKey(decoded.inputMint).__str__(), "inputAmount": str(decoded.inputAmount), "outputMint": PublicKey(decoded.outputMint).__str__(), "outputAmount": str(decoded.outputAmount) } print(result)
更省心的方式:用Anchorpy直接解析
如果你不想自己写结构体,可以用Anchor官方工具anchorpy加载Jupiter的IDL直接解析事件,代码更简洁:
from solana.rpc.api import Client from anchorpy import Program, EventParser, Idl # 初始化RPC客户端 client = Client("https://api.mainnet-beta.solana.com") tx_sig = "DuLpVzC9omVsCM3AEPzd9v3QryN51FDeXq6aZY9Fos6dhSip3uRofsdwTCsA5kUGbQRv8W6aCmHRnbt7jtp8iXP" jupiter_program_id = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc" # 加载Jupiter的IDL(可从Jupiter官方仓库获取) idl = Idl.from_json(open("jupiter_idl.json").read()) program = Program(idl, jupiter_program_id, client) # 获取交易日志 tx_response = client.get_transaction(tx_sig, encoding="jsonParsed", max_supported_transaction_version=0) logs = tx_response["result"]["meta"]["logs"] # 解析所有事件并筛选Swap事件 event_parser = EventParser(program.idl) events = [] for log in logs: event_parser.parse_log(log, lambda evt: events.append(evt)) swap_event = next(evt for evt in events if evt.name == "Swap") print(swap_event.data)
额外说明
- 字节序:Solana上所有
u64类型数据都是小端序(Little-Endian),所以用Uint64ul完全正确。 - 公钥转换:32字节原始公钥用
base58.b58encode(decoded.amm).decode()和PublicKey(decoded.amm).__str__()结果一致,选你习惯的方式即可。
备注:内容来源于stack exchange,提问作者a14stoner




