Skip to content

Frontend Integration

Connecting a frontend to Zink uses the familiar SVM app stack: standard client libraries, wallet adapters, and a Zink RPC endpoint. This page covers practical patterns for browser-based, mobile, and desktop applications.

Upstream-compatible

Frontend libraries that speak standard Solana JSON-RPC work with Zink by changing the RPC URL. The JSON-RPC and WebSocket protocols are the same.

Choosing a client library

The Solana TypeScript ecosystem has evolved through several packages. Here is the current landscape:

PackageStatusNotes
@solana/kitCurrentModular, tree-shakeable successor to web3.js. Recommended for new projects.
@solana/web3.js (v2)CurrentRe-export of @solana/kit for backwards-compatible package name.
@solana/web3.js (v1.x)LegacyWidely used. Still works but is in maintenance mode.
@solana/web3-compatBridgeCompatibility layer to ease migration from v1 to v2 APIs.
@solana/clientCurrentLower-level RPC client used internally by @solana/kit.
@solana/react-hooksCurrentReact bindings for @solana/kit — connection, wallet, account subscriptions.

Zink recommendation

Use the SDK version recommended for your application stack and deployed program versions. Consistency across the ecosystem reduces integration friction.

Establishing a connection

typescript
import { createSolanaRpc, createSolanaRpcSubscriptions } from "@solana/kit";

const rpc = createSolanaRpc("https://testnet-rpc.z.ink");
const rpcSubscriptions = createSolanaRpcSubscriptions("wss://testnet-rpc.z.ink");

// Fetch a recent blockhash
const { value: blockhash } = await rpc
  .getLatestBlockhash({ commitment: "confirmed" })
  .send();

With @solana/web3.js v1 (legacy)

typescript
import { Connection } from "@solana/web3.js";

const connection = new Connection("https://testnet-rpc.z.ink", "confirmed");
const blockHeight = await connection.getBlockHeight();

Zink-specific

The currently published public endpoint is https://testnet-rpc.z.ink. For subscriptions, use the matching WebSocket host (wss://testnet-rpc.z.ink) or the operator-provided subscription URL for unpublished environments.

Wallet adapter setup

The @solana/wallet-adapter libraries provide a framework-agnostic interface for connecting browser extension wallets (Phantom, Backpack, Solflare, etc.) to your application.

React setup

bash
npm install @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets
tsx
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-wallets";

const wallets = [new PhantomWalletAdapter()];

function App() {
  return (
    <ConnectionProvider endpoint="https://testnet-rpc.z.ink">
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
          {/* Your app */}
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
}

Wallets connect to whatever RPC endpoint your application specifies — no wallet-side configuration is needed to use Zink. The wallet signs transactions locally; your app submits them to the Zink RPC.

With @solana/react-hooks

If you are building with @solana/kit, the @solana/react-hooks package provides React hooks that integrate directly with the newer API:

tsx
import { SolanaProvider } from "@solana/react-hooks";

function App() {
  return (
    <SolanaProvider
      rpcUrl="https://testnet-rpc.z.ink"
      wsUrl="wss://testnet-rpc.z.ink"
    >
      {/* Your app */}
    </SolanaProvider>
  );
}

Building and sending transactions

Constructing a transaction

typescript
import {
  createTransactionMessage,
  setTransactionMessageFeePayer,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstruction,
  compileTransaction,
} from "@solana/kit";

const message = createTransactionMessage({ version: 0 });
const withFeePayer = setTransactionMessageFeePayer(walletAddress, message);
const withBlockhash = setTransactionMessageLifetimeUsingBlockhash(
  blockhash,
  withFeePayer
);
const withInstruction = appendTransactionMessageInstruction(
  myInstruction,
  withBlockhash
);
const transaction = compileTransaction(withInstruction);

Sending and confirming

typescript
const signature = await rpc.sendTransaction(signedTransaction).send();

// Wait for confirmation
const confirmation = await rpc
  .confirmTransaction(signature, { commitment: "confirmed" })
  .send();

Priority fees

If the Zink cluster is under load, you can attach a priority fee to improve transaction landing rates. Priority fees are set via a Compute Budget instruction:

typescript
import { ComputeBudgetProgram } from "@solana/web3.js";

// Set the price you're willing to pay per compute unit (in micro-lamports)
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
  microLamports: 1000,
});

// Optionally cap your compute unit budget
const computeLimitIx = ComputeBudgetProgram.setComputeUnitLimit({
  units: 200_000,
});

Zink-specific

Fee parameters on Zink may differ from Solana mainnet. Query the cluster's recent priority fee levels with getRecentPrioritizationFees to calibrate your fee strategy. See Fees for details.

Address Lookup Tables

Versioned transactions (v0) support Address Lookup Tables (ALTs) to compress transaction size when referencing many accounts. This is the same mechanism as Solana mainnet:

typescript
import { AddressLookupTableProgram } from "@solana/web3.js";

// Create a lookup table
const [createIx, lookupTableAddress] =
  AddressLookupTableProgram.createLookupTable({
    authority: wallet.publicKey,
    payer: wallet.publicKey,
    recentSlot: await connection.getSlot(),
  });

// Extend the table with addresses
const extendIx = AddressLookupTableProgram.extendLookupTable({
  lookupTable: lookupTableAddress,
  authority: wallet.publicKey,
  payer: wallet.publicKey,
  addresses: [programId, tokenMint, /* ... */],
});

Using ALTs is recommended when your transactions reference more than ~20 accounts — common in complex DeFi or game interactions.

Subscribing to account changes

Real-time subscriptions use WebSocket under the hood. This is useful for updating UI when on-chain state changes.

With @solana/kit

typescript
const accountNotifications = await rpcSubscriptions
  .accountNotifications(accountAddress, { commitment: "confirmed" })
  .subscribe();

for await (const notification of accountNotifications) {
  console.log("Account updated:", notification);
}

With @solana/web3.js v1

typescript
connection.onAccountChange(accountPublicKey, (accountInfo) => {
  console.log("Account data changed:", accountInfo.data);
});

Network switching

If your application needs to support multiple clusters, keep published endpoints explicit and inject unpublished ones through environment configuration:

typescript
const CLUSTERS = {
  "zink-testnet": "https://testnet-rpc.z.ink",
  "solana-mainnet": "https://api.mainnet-beta.solana.com",
} as const;

// For unpublished Zink Mainnet or operator-only environments, load the URL
// from an environment variable instead of hardcoding a guessed hostname.
type ClusterName = keyof typeof CLUSTERS;

function getConnection(cluster: ClusterName) {
  return new Connection(CLUSTERS[cluster], "confirmed");
}

Wallet adapters handle the endpoint you give them — users do not need to manually switch networks in their wallet.

Error handling patterns

Transactions can fail for many reasons. Common frontend error handling:

typescript
try {
  const signature = await sendTransaction(transaction, connection);
  await connection.confirmTransaction(signature, "confirmed");
} catch (err) {
  if (err instanceof SendTransactionError) {
    // Transaction simulation failed — inspect logs
    const logs = err.logs;
    console.error("Transaction failed:", logs);
  }
}

Simulation failures include program logs that pinpoint which instruction failed and why. Always surface these logs during development.

Next steps

  • SDKs — full SDK reference for TypeScript, Rust, Python, and more
  • Fees — understanding compute budgets and priority fees on Zink
  • Transactions — transaction anatomy and versioned transaction details
  • Clusters & Environments — Zink endpoint URLs

Zink is a general-purpose SVM network for programs, operators, and bridge integrations.