Skip to content

Getting Started

Installation

npm install @arkonix.xyz/arkonix-vault-sdk viem @tanstack/react-query
pnpm add @arkonix.xyz/arkonix-vault-sdk viem @tanstack/react-query

Requirements

Dependency Kind Version
viem direct dependency ^2.43.3
@tanstack/react-query direct dependency ^5.90.12
react peer dependency (required) >=18.0.0
react-native peer dependency (optional — RN apps only) >=0.70.0

The package ships ESM + CJS + .d.ts (dist/index.js, dist/index.cjs, dist/index.d.ts / dist/index.d.cts) with sideEffects: false (tree-shakeable). Named exports only — there is no default export.

Quickstart: React hooks

1. Set up the providers

A QueryClientProvider (from @tanstack/react-query) must be above VaultProvider. If your app already uses react-query, reuse the existing provider — don't add a second. Wrap only the vault section of your app, not the whole app.

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { VaultProvider } from "@arkonix.xyz/arkonix-vault-sdk";

const queryClient = new QueryClient();

<QueryClientProvider client={queryClient}>
  <VaultProvider
    config={{
      chainId: 42161,
      rpcUrl: "https://arb1.arbitrum.io/rpc",
      arkonixAPI: { baseUrl: "https://api.arkonix.xyz" },
    }}
  >
    <VaultWidget />
  </VaultProvider>
</QueryClientProvider>

Note

Without walletAdapter, the provider defaults to the injected window.ethereum wallet on web. Most partners already have a wallet stack (wagmi, RainbowKit, Privy) — see Wallet Integration for the recommended adapter setup. React Native apps must pass a custom adapter.

2. Read vault financials from an address alone

import { useVaultFinancials, useReturnHistory } from "@arkonix.xyz/arkonix-vault-sdk";

function VaultDashboard({ vaultAddress }: { vaultAddress: `0x${string}` }) {
  const { data: fin, isLoading } = useVaultFinancials(vaultAddress);
  const { data: history } = useReturnHistory(fin?.shareClassId, { days: 90 });

  if (isLoading || !fin) return <div>Loading…</div>;

  return (
    <div>
      <p>NAV (TVL): ${fin.tvlUsd.toLocaleString()}</p>
      <p>Share price: {fin.sharePrice ?? "—"}</p>
      {/* null ≠ 0: render a placeholder for insufficient history */}
      <p>Return (7d): {fin.return7d != null ? `${fin.return7d}%` : "—"}</p>
      <p>Return (all-time, annualized): {fin.returnAllTime != null ? `${fin.returnAllTime}%` : "—"}</p>
      {history && <SparklineChart points={history.points} />}
    </div>
  );
}

Return fields are nullable and not APY

null means "not enough history" — never coerce it to 0. return7d/30d/90d are cumulative window returns, not annualized. Read Working with Financial Data before rendering any return figure.

3. Deposit

import { useDeposit, useVaultMetadata } from "@arkonix.xyz/arkonix-vault-sdk";

function DepositForm({ vaultAddress }: { vaultAddress: `0x${string}` }) {
  const { data: meta } = useVaultMetadata(vaultAddress);
  const [amount, setAmount] = useState("");

  const { deposit, txState, error, reset } = useDeposit(
    vaultAddress, meta?.asset, meta?.assetDecimals, meta?.vaultType,
  );

  return (
    <div>
      <input value={amount} onChange={(e) => setAmount(e.target.value)} placeholder="100" />
      <button onClick={() => deposit(amount)} disabled={txState !== "idle"}>
        {txState === "approving" ? "Approving…" :
         txState === "pending" ? "Depositing…" :
         txState === "confirming" ? "Confirming…" :
         txState === "success" ? "Done!" : "Deposit"}
      </button>
      {error && <p style={{ color: "red" }}>{error}</p>}
    </div>
  );
}

useVaultMetadata is step 1 of every integration — it yields the asset, share, assetDecimals, shareDecimals, and vaultType that all other hooks take as parameters. For the full deposit/redeem/cancel lifecycle, see Deposit & Redeem Flows.

Quickstart: Standalone (no React)

All three core classes are static-method namespaces — never instantiated. They take a viem PublicClient and (for writes) a SendTransactionFn:

import { createPublicClient, http } from "viem";
import { arbitrum } from "viem/chains";
import { VaultReader, VaultActions } from "@arkonix.xyz/arkonix-vault-sdk";

const client = createPublicClient({ chain: arbitrum, transport: http(rpcUrl) });

// Bridge to any wallet: WalletConnect, Privy, ethers, a relayer…
const sendTransaction = async (tx) =>
  myWallet.sendTransaction({ to: tx.to, data: tx.data, value: tx.value });

const meta = await VaultReader.getMetadata(client, vaultAddress);
const state = await VaultReader.getUserState(client, vaultAddress, userAddress, meta.vaultType, meta.assetDecimals);

const { depositHash } = await VaultActions.deposit(
  client, sendTransaction, vaultAddress, "100", userAddress,
  meta.asset, meta.assetDecimals, meta.vaultType,
);

await VaultActions.requestRedeem(client, sendTransaction, vaultAddress, "10", userAddress, meta.shareDecimals);

if (state.hasClaimableRedeem) {
  await VaultActions.claimRedeem(client, sendTransaction, vaultAddress, state.claimableRedeemShares, userAddress);
}

Note

Unlike the hooks (which surface failures in error state), VaultActions methods throw on failure — wrap them in try/catch. See the Core Reference.

For standalone financial data, use ArkonixAPIClient.

Next steps