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

@securitize/solana-bridge-sdk

v0.2.0

Published

Securitize Bridge Solana program SDK

Readme

@securitize/solana-bridge-sdk

TypeScript SDK for the Securitize DS-token bridge on Solana. Wraps the securitize_bridge Anchor program: instruction builders, PDA helpers, executor-quote utilities, and a high-level SecuritizeBridgeClient class that handles ALT resolution, signing, and retries.

yarn add @securitize/solana-bridge-sdk

Entry points

  • SecuritizeBridgeClient — high-level async client (signs, submits, syncs state).
  • SecuritizeBridgeClient.instructions — stateless instruction builders returning TransactionInstruction[]. Use when you compose your own transaction / submission flow.
  • SecuritizeBridgeClient.transactions — same builders wrapped as legacy Transaction factories.
  • PDA helpers (bridgeConfigPda, bridgeAddressPda, sentMessagePda, …) from src/utils.ts.
  • Executor-quote utilities (fetchExecutionQuote, parsePayeeFromSignedQuote) from src/executor-quote.ts.

Required payer SOL balance

Reserve ≥ 0.01 SOL above wormhole_fee + exec_amount when calling bridge_ds_tokens. The on-chain handler only checks that lower bound; a successful transaction additionally needs rent for the posted Wormhole message account, a one-time rent for the per-mint sequence tracker on the first send, the payer rent-exempt minimum, and tx / priority fees.

Concurrency semantics (outbound bridging)

Outbound bridgeDsTokens performs a Wormhole post_message CPI. Wormhole maintains one sequence-tracker account per emitter (per-mint in our case). Every successful outbound send mutates that account, and Solana runtime serializes writes to it.

Two consequences follow:

  1. Per-mint throughput ceiling. Concurrent sends for the same asset mint do not run in parallel; they queue. Effective throughput is bounded by single-account contention (roughly one confirmed send per slot in the worst case).
  2. Race window on pre-built transactions. The wormhole_message account is a PDA derived from the current sequence value. The SDK reads that value from RPC to derive the PDA. If a competing transaction lands between the read and the on-chain check, the program reverts with InvalidMessage (Anchor error code 6007).

This is inherent to Wormhole + Solana — it is not bridge-specific and cannot be eliminated on-chain. The SDK absorbs it with automatic retries.

Default retry behavior

SecuritizeBridgeClient.bridgeDsTokens(params) automatically retries on InvalidMessage:

| Option | Default | Effect | | ------------------------------------- | -------- | -------------------------------------------------------------------------------------------------- | | retry.maxAttempts | 3 | Total attempts including the first. Set to 1 to disable retries. | | retry.retryableCodes | [6007] | Only InvalidMessage by default. Other errors (auth, balance, paused, …) are not retried. | | retry.enablePriorityFeeAfterAttempt | 2 | Attempt number (1-indexed) from which withPriorityFee: true is forced. | | retry.refreshExecutorQuote | unset | Optional async callback; when set, invoked before each retry to refresh short-TTL executor quotes. | | retry.onRetry | unset | Hook ({ attempt, nextAttempt, errorCode }) => void for logging / metrics. |

Each retry rebuilds the instruction set from scratch — that re-fetches the current sequence value and re-derives wormhole_message, closing the race window.

Refreshing short-TTL executor quotes

If you build the signed executor quote far in advance of submitting (minutes), the quote may expire between retries. Pass refreshExecutorQuote so that each retry picks up a fresh quote:

const refreshExecutorQuote = async () => {
  const quote = await client.getExecutionQuote({ targetChain });
  return {
    signedQuoteBytes: quote.signedQuoteBytes,
    execAmount: quote.estimatedCost,
  };
};

await client.bridgeDsTokens({
  targetChain,
  amount,
  recipient,
  execAmount,
  signedQuoteBytes,
  investor,
  revokeTokensAccounts,
  executorAccounts,
  retry: { refreshExecutorQuote },
});

Building your own submission flow

The retry loop lives in SecuritizeBridgeClient.bridgeDsTokens. If you call SecuritizeBridgeClient.instructions.bridgeDsTokens(...) directly and submit via your own transport, you must implement equivalent retry logic yourself:

  • Catch the send/confirm error and inspect it via extractAnchorErrorCode(err) (exported from src/utils.ts). It matches both native Anchor logs (Error Number: N), runtime hex logs (Custom program error: 0xNNNN), and stringified TransactionError ({"Custom":N}).
  • Compare the code against BRIDGE_ERROR_CODE.INVALID_MESSAGE (6007, exported from src/constants.ts).
  • On match, rebuild the instruction set (which re-reads the sequence) and resubmit. Add a priority-fee compute-budget ix on retry to outbid contending senders.

Griefing failure mode

An adversary can, for a cost, induce InvalidMessage reverts on a victim by landing their own bridge_ds_tokens transaction between the victim's RPC read and on-chain execution. The attack does not cause loss of funds (all state changes happen after the wormhole_message check) and is bounded by the attacker's willingness to pay Wormhole + executor fees and burn bridge-minimum amounts via the RBAC revoke_tokens CPI. The default retry with priority-fee escalation neutralises non-persistent griefing; persistent adversaries raise the victim's effective cost but cannot deny service indefinitely.

Throughput planning

Product flows that expect multiple users to bridge the same mint concurrently should:

  • Treat per-mint outbound throughput as bounded. Do not design UX around parallel sub-second completion for the same mint.
  • Expect and tolerate InvalidMessage retries in metrics — they are not bugs.
  • Surface retry attempts to the UI (e.g. "re-submitting due to concurrent bridge activity") rather than treating the first revert as a failure.

Related packages

  • @securitize/solana-bridge-cli (securitize-bridge binary) — operational CLI built on this SDK.
  • @securitize/solana-usdc-bridge-sdk — sibling SDK for the USDC CCTP bridge (no Wormhole sequence contention; CCTP has a different on-chain flow).

Development

This package is part of the bc-solana-bridge-sc monorepo. From the repo root:

yarn build        # anchor build
yarn sync-sdk-all # copy IDL / types into SDK src
yarn build:packages