You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Solana上正确解码Jupiter Swap事件?

如何在Solana上正确解码Jupiter Swap事件?

你好!看了你的问题,你现在主要踩了两个关键的坑,导致解析结果完全不对,咱们一步步来修正:

核心问题分析

  1. 用错了解析数据源:你直接使用了整个交易的原始Hex数据,但Jupiter的Swap事件字节是交易执行后,Jupiter程序输出到日志或事件账户的特定数据段,根本不是整个交易的Data部分。
  2. 数据类型匹配错误:你用有符号的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

火山引擎 最新活动