npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ifx-run/sdk

v0.1.1

Published

TypeScript SDK for Ifx — instruction builders, Expr codec, FrameScratch. Default program id: mainnet.

Readme

@ifx-run/sdk

← Ifx 项目主页

English | 中文

Ifx 的 TypeScript SDK,分两层,不包装 RPC / 钱包

集群: npm 默认指向 主网DEFAULT_IFX_PROGRAM_ID = IFX_MAINNET_PROGRAM_ID)。仓库 Surfpool / 集成测试须显式传 IFX_LOCALNET_PROGRAM_ID。Devnet:IFX_DEVNET_PROGRAM_ID

  1. FrameScratchlet* 规划 binding,ix* / letBuilder().buildIx() 产出指令;用 tx.add(…) 组装交易
  2. expr / Expr / ScratchValue — 构造器、链上 wire 类型、类型化 Frame binding

ix.ts 中的底层 createIx* 仍导出;业务代码优先用 FrameScratch 方法。

签名、发送、读取账户:用你现有的 Anchor Provider / wallet / connection.getAccountInfo。Frame 反序列化可用 decodeFrameAccount(布局辅助),或与 Anchor IDL 生成的 program.account 并存。

安装

当前版本: 0.1.1(默认主网;与 [email protected][email protected] 对齐)。

npm install @ifx-run/sdk @anchor-lang/core @solana/web3.js bn.js

锁定版本:npm install @ifx-run/[email protected]

创建 Frame,再使用

Tx 1 — 开通(单独一笔;不要与 swap/结算等混在同一 tx):

import { randomBytes } from "crypto";
import { Transaction } from "@solana/web3.js";
import { FrameScratch, DEFAULT_TAPE_LEN } from "@ifx-run/sdk";

const tapeLen = DEFAULT_TAPE_LEN; // 512;链上最大 MAX_FRAME_TAPE_LEN;典型 256–8192
const frameId = randomBytes(32); // 仅 create 用的 salt;Tx 1 后持久化 scratch.frame + tapeLen(frameId 可丢弃)
const { scratch, ixCreate, frame } = FrameScratch.planPublicFrame({
  payer,
  frameId,
  tapeLen,
});

await provider.sendAndConfirm(new Transaction().add(ixCreate));

默认(公共 Frame): planPublicFrameauthority 设为 Frame PDA(off-curve)— 任何人可写。生产可用:每个原子单元(单笔 tx 或已落地 bundle)开头 ixReset()frame-authority.zh-CN.md §3.4。reset/let 无需额外 signer;不能 close 收 rent。预签只读且中间不能 reset、或需要 close 时用 planNewFrame

Tx 2 — 业务(另一次请求 / 任务;reset + let / assert / CPI)。同进程复用 Tx 1 的 scratch;跨任务重建见 examples/minimal-frame.ts

import { Transaction } from "@solana/web3.js";
import { expr, FrameScratch } from "@ifx-run/sdk";

const tx = new Transaction();
tx.add(scratch.ixReset());
const target = scratch.letConstU64(10);
tx.add(scratch.ixLet(target));
tx.add(scratch.ixAssert(expr.nonZero(target)));
await provider.sendAndConfirm(tx);

可选 — 私有 / 可关闭 Frame(on-curve authorityreset/let;日后 close 回收 rent)。用于 bundle / nonce 防投毒等场景 — frame-authority.zh-CN.md

const { ixCreate } = FrameScratch.planNewFrame({
  payer,
  frameId,
  authority: payer, // 通常与业务 tx 已签名的 bot 热钱包相同
  tapeLen,
});
// Tx 2:new FrameScratch(frame, tapeLen, 0, 0, undefined, payer)

仅需 create 指令时用 FrameScratch.ixCreateFrame(params)(参数同 planNewFrame / planPublicFrame)。

执行后确认结果:看 Ifx 链上 logs(条件、rawCpi / patched CPI、assert 等),不要在生产代码里 fetchDecodedFrame 读 tape。decode / fromFrame / refreshFromChain 仅用于 测试与本地调试(见 tests/integration/)。

单条 binding(scratch.let* + ixLet

一条 ifx_let 一个值 — 在 FrameScratch 上规划,用 scratch.ixLet 发出:

const snap = scratch.letLamports(userMeta);
tx.add(scratch.ixLet(snap));
// 后续:expr.sub(other, snap)

需要账户时,ScratchValue 自带 letRemaining(单账户 let 为索引 0)。

多条 binding(scratch.letBuilder

传入 公钥或 AccountMeta;builder 会对 remaining_accounts 去重并自动分配 AccountLamports / AccountDataSlice 下标:

const scratch = new FrameScratch(frame, 256);
const letBuilder = scratch.letBuilder();

const y0 = letBuilder.lamports(user);
const x0 = letBuilder.lamports(userAta);

tx.add(letBuilder.buildIx());

finish() 返回 { args, bindings, remaining, scratch },便于拆开使用。

表达式(第三部分)

expr / FrameScratch / ScratchValue / LetIxBuilder / ifElseArgs / rawCpiPatch — 类型化 SDK,链上类型 Expr 不变。Cond = TypedExpr<"bool">expr.gtexpr.ge 等) ScratchValue<"bool">expr.add / expr.sub 直接收 ScratchValue | TypedExpr

Tape record 布局

每条 binding 写入 [ty:1][payload:ty.size()]Frame::tape;wire 引用 Value.index(binding 序号,u8)。链下类型在 ScratchValueplanRecordOffsetstape-layout.ts)须与链上 plan_record_offsets 一致。

创建时:tapeLen 链上最大 65_535推荐 DEFAULT_TAPE_LEN(512),复杂编排一般不超过 RECOMMENDED_TAPE_LEN_MAX(8192) — 更大 Frame 租金与 let/reset CU 更高(见 frame-cu-optimization.zh-CN.md)。indexCap = min(256, floor(tapeLen / 2))。append 失败:IndexCapReachedTapeOutOfBounds — 见 errors.zh-CN.md

ifx_assert_multi wire 最多 255 条 cond(MAX_ASSERT_MULTI_CONDS);建议每条 ix 合并 3–10 条 guard(RECOMMENDED_ASSERT_MULTI_MAX),避免整笔 tx CU 过高;更多 guard 拆成多条 multi 或 N× ifx_assert — 见 r4-assert-multi.zh-CN.md

extend_frame / shrink_frame 创建时一次性分配 tapeLen + 固定 payload_atnew FrameScratch(framePk, tapeLen) 做链下校验。

FrameScratchtapeLen

何时才 let(落盘到 Frame)

  • 要落盘: 后面的 ifx_assertifx_patched_cpiRawCpiPatch、或更晚的 ifx_let 里还会用到的值。

  • 不要落盘: 仅为书写方便的中间量;改在同一条 letEval 里写嵌套 Expr,或把比较写进 ifx_assert

  • FrameScratch.planPublicFrame(...):一次性 create;authority = Frame PDA。

  • FrameScratch.forPublicFrame({ framePubkey, ... })生产路径 — 已有公共 Frame 的 planner(authority === frame)。

  • FrameScratch.planNewFrame(...):可选 — 需 close、§3.7 预签边角、或纵深防御。

  • Frame 地址(闭环)frame_id 仅用于 create 派生 PDA。Tx 1 后持久化 scratch.frame + tapeLen

  • forPublicFramenew FrameScratch(...):Tx 2 重建 planner;公共 Frame 优先 forPublicFrame,勿手写 authority = frame

  • FrameScratch.fromFrame / refreshFromChain:仅 测试与本地调试(如同 repo 的 tests/);不要用于生产业务路径。

SPL Token 与 Token-2022(应用层)

链上 ifx_let 对 legacy SPL Token 与 Token-2022 有 typed opcode(链上 StateWithExtensions unpack)。SDK 在 LetIxBuilder 上封装 —— 直接传账户即可,remaining_accounts 下标自动分配并按 pubkey 去重:

const scratch = new FrameScratch(frame, 256);
const batch = scratch.letBuilder();
const amount = batch.splTokenAmount(tokenAccount); // legacy
const withheld = batch.splToken2022TransferFeeWithheld(token2022Ata);
tx.add(batch.buildIx());

| letBuilder 方法 | 字段 | |-------------------|------| | splTokenAmount / splTokenDelegatedAmount | Legacy token account | | splMintSupply / splMintDecimals | Legacy mint | | splToken2022Amount / splToken2022DelegatedAmount / splToken2022AccountState | Token-2022 account 基础字段 | | splToken2022TransferFeeWithheld | TransferFeeAmount.withheld_amount | | splToken2022MintSupply / splToken2022MintDecimals | Token-2022 mint 基础字段 | | splToken2022MintTransferFeeBasisPoints / splToken2022MintTransferFeeMaximum / splToken2022MintWithheldAmount | TransferFee mint 扩展 | | splToken2022MintDefaultAccountState | DefaultAccountState 扩展 |

链上缺少对应 Token-2022 extension → Token2022ExtensionNotPresent。typed opcode 未覆盖的字段用 accountDataSlice(account, expectedOwnerProgram, ty, offset)

常量:sdk/src/spl/layout.ts(仅 legacy 固定布局)。

Structured CPI(官方 System / SPL / Token-2022)— 默认

目标指令在 on-chain registry 内时用 structuredCpi(),无需手编 data 偏移。见 structured-cpi-patches.zh-CN.md。L0–L3 示例与 sdk/examples/ 对 System transfer、SPL Transfer、Token-2022 BurnChecked 等均采用此路径。

import { structuredCpi, structuredCpiPatch } from "@ifx-run/sdk";
import { SystemProgram } from "@solana/web3.js";
import { createTransferInstruction } from "@solana/spl-token";

const settle = scratch.letConstU64(1_000_000);
const sponsorXfer = structuredCpi(
  SystemProgram.transfer({ fromPubkey: payer, toPubkey: recipient, lamports: 0 }),
  structuredCpiPatch.systemTransfer(settle)
).build();
tx.add(scratch.ixCpi(sponsorXfer));

const usdcOut = scratch.letSplTokenAmount(userUsdcAta);
const hop2 = structuredCpi(
  createTransferInstruction(userUsdcAta, poolUsdcAta, user, 0),
  structuredCpiPatch.tokenTransfer(usdcOut)
).build();
tx.add(scratch.ixCpi(hop2));

InitializeMint2 + Frame Pubkeytests/ifx_structured_cpi_initialize_mint.ts

默认不传 remaining — 账户来自模板指令([programId, …keys])。仅在合并进更长列表时传入(例如 ifx_if_elseifx_let 共用 remaining);只传 PublicKey[] 会丢失 signer/writable。

RawPatched CPI(rawCpi / ifx_patched_cpi)— type-unsafe 逃生口

面向 DEX 或自定义 programdata layout 不在 structured registry)— 模板 ix + 字节覆盖。program id 与 layout 由交易构造者负责(类似 Rust unsafe);Ifx 不对 Raw CPI 目标做白名单。registry 能覆盖时请用 structuredCpi() — 见 raw-cpi-patches.zh-CN.md

import { rawCpi, rawCpiPatch } from "@ifx-run/sdk";

const amountIn = scratch.letSplTokenAmount(userUsdcAta);

const built = rawCpi(dexHop2Template, {
  patches: [rawCpiPatch(amountInOffset, amountIn)],
}).build();

tx.add(scratch.ixCpi(built));

rawCpiPatch(dataOffset, value) 从 Frame tape 拷贝到 data[dataOffset..]链上测试覆盖: tests/ifx.tstests/ifx_cpi_edges.tstests/ifx_negative.ts;wire codec:tests/sdk_patch_codec.tstests/sdk_if_else_generic_codec.ts

无 patch:staticCpi(template)ifx_if_elsearm.cpi(step.staticStep);无条件时也可直接把目标指令放进交易。

ifx_if_else 分支 arm

每条分支为 IfElseArmSkipRevert,或 1–254Cpi 步。SDK:

import { arm, ifElseArgs, expr, staticCpi } from "@ifx-run/sdk";

// 指令 data 固定 — 静态 Cpi 步
const close = staticCpi(closeAccountIx);
ifElseArgs(expr.isZero(amount), arm.cpi(close.staticStep));

// cond 为真 → patched Cpi 步;为假 → skip(else 默认)
ifElseArgs(flag, arm.cpi(built.cpi));

选中 Revert 分支时整笔 revert(IfElseRevert)。与分支无关的全局条件用 ifx_assert

不负责什么

| 不做 | 用什么 | |------|--------| | 发交易、签名 | provider.sendAndConfirm / wallet adapter | | 自定义 Client/Connection | 不需要 | | 重复 Anchor IDL 已能生成的账户 fetch | program.account.frame.fetch(若你已生成 client) |

decodeFrameAccount / framePdalayout 包:解码 Frame 账户仅供测试与本地调试(集成测试断言 tape 写回)。生产环境以 transaction logs 观测 Ifx 行为;不要在生产里 RPC fetch Frame 做规划或验收。FrameScratch 只做布局规划,没有缓冲区,也不提供 read API。

IDL

根目录 idl/ifx.jsonnpm run idl:generateanchor build)更新;Expr 在 program 内用静态 JSON + 自定义 IdlBuild(见 programs/ifx/src/state/expr_idl.rs)。npm run idl:sync 生成 sdk/src/idl/ifx.ts。含 Expr 的 instruction data 仍用本 SDK 的 createIx* / codec.ts

发布后 npm 包内附带 dist/idl/ifx.jsonimport "@ifx-run/sdk/idl.json"require("@ifx-run/sdk/idl.json"),见 package.json exports)。

版本与 Program ID

| 项 | 说明 | |----|------| | npm | @ifx-run/sdk 语义化版本见 CHANGELOG.md | | 链上 | DEFAULT_IFX_PROGRAM_ID(= 主网)· IFX_MAINNET_PROGRAM_ID · IFX_DEVNET_PROGRAM_ID · IFX_LOCALNET_PROGRAM_IDconstants.ts) | | IDL | idl/ifx.jsonmetadata.version 与 program crate 版本应对齐发布说明 | | 破坏性变更 | 指令 discriminator、Expr / U8LenVec / U16LenVec wire、Frame tape 布局 → 升 major 并写 changelog |

省略 programId 即连主网(DEFAULT_IFX_PROGRAM_ID)。Devnet / localnet / 自定义 cluster:在 planNewFrame / 构造函数传 IFX_DEVNET_PROGRAM_IDIFX_LOCALNET_PROGRAM_ID。单笔 ix 覆盖:scratch.ixReset({ programId })

示例

仓库内 examples/(不随 npm 发布):L0 minimal-frame.ts · guardrail guardrail-lamports-delta.ts / guardrail-token-balance.ts · L1 dust-destroy-token2022.ts(patched + static CPI)。

其它客户端:Go SDK · Rust SDKifx-sdk)。

维护者

npm 发布流程见 PUBLISHING.zh-CN.md