Skip to content

Getting started with the SDK

@hobba-io/core is the Hobba SDK - the exact on-chain logic behind app.hobba.io, published as an npm package. The app, the embeddable widget and partner integrations all run this same code, so an SDK integration behaves identically to Hobba’s own UI: same lender routing, same account resolution, same math.

Use the SDK when you want Hobba under your own UI. If you just want a drop-in component, use the widget instead.

Terminal window
npm install @hobba-io/core @coral-xyz/anchor @solana/web3.js @solana/spl-token bn.js

The Solana stack is declared as peer dependencies so your bundle holds exactly one copy of @solana/web3.js / bn.js (two copies break instanceof PublicKey checks).

Bundler required. The package ships ESM targeted at bundler consumers (Next.js/webpack, Vite, esbuild/tsup). It is not consumable from bare Node ESM without a bundler or a loader such as tsx.

The program id baked into PROGRAM_ID is chosen at build time from env variables your bundler must define:

EnvProgram
NEXT_PUBLIC_MAINNET=trueMainnet - Hobbakk1LmW2DhE4nAKnCeU1iK7V7pKHTq3ihaE2i8qG
NEXT_PUBLIC_STAGING=trueStaging - soBBAHNhFyWF4QBCK9BJLVkX6d6NZt37ozNaPV5aq3H
(neither)Local development

Next.js inlines NEXT_PUBLIC_* automatically; with other bundlers, define process.env.NEXT_PUBLIC_MAINNET yourself. For a production integration, set NEXT_PUBLIC_MAINNET=true.

Almost every SDK function takes the same trio:

import { Connection } from "@solana/web3.js";
const connection = new Connection(RPC_URL); // 1. your RPC connection
const signer = wallet; // 2. a HobbaSigner
const apiBaseUrl = "https://app.hobba.io"; // 3. the Hobba backend
  1. connection - a web3.js Connection used for reads, simulation and submission. Use your own RPC provider.

  2. signer - anything matching HobbaSigner:

    interface HobbaSigner {
    publicKey: PublicKey | null;
    signTransaction?: <T extends Transaction | VersionedTransaction>(tx: T) => Promise<T>;
    }

    Both wallet-adapter’s WalletContextState and a raw injected provider (window.solana, window.solflare) satisfy this structurally - no cast needed.

  3. apiBaseUrl - the Hobba backend serving helper routes the SDK calls (/api/juplend-operate, /api/lut, /api/rates, prices, …). Point it at https://app.hobba.io. The same origin allowlist as the widget applies to browser calls - see Backend & CORS for getting your origin allowlisted or proxying.

A wallet must be allowlisted once before it can transact - the same referral-redeem step the widget needs. A non-allowlisted wallet’s transactions fail; the SDK surfaces this as the NOT_ALLOWLISTED error code (see below).

executeDepositBorrow is the one-call onboarding flow - it initializes first-time users, routes to the best lender, and executes the deposit and borrow:

import {
executeDepositBorrow,
parseCollateral,
parseUsdc,
CBBTC_MINT,
} from "@hobba-io/core";
const { depositSig, borrowSig, lender } = await executeDepositBorrow({
connection,
signer,
collateralMint: CBBTC_MINT, // or SOL_MINT
depositAmount: parseCollateral("0.01", CBBTC_MINT),
borrowAmount: parseUsdc("250"),
apiBaseUrl: "https://app.hobba.io",
onStep: (s) => console.log(s), // progress for your UI
});

See Deposit & borrow for the full breakdown, then the per-action pages - Deposit, Borrow, Repay, Withdraw - for managing the position.

All amounts cross the SDK boundary as BN base units - never floats:

AssetBase unitHelper
cbBTC1e8 (satoshis)parseCollateral("0.01", CBBTC_MINT)
SOL1e9 (lamports)parseCollateral("1.5", SOL_MINT)
USDC1e6 (micro-USDC)parseUsdc("250")

Formatting helpers (formatUsdcShort, formatCollateralShort, …) convert back for display.

The execute flows throw plain Errors; map them onto stable codes with classifyError:

import { classifyError } from "@hobba-io/core";
try {
await executeAction({ /* … */ });
} catch (e) {
const err = classifyError(e);
switch (err.code) {
case "WALLET_NOT_CONNECTED": /* prompt connect */ break;
case "NOT_ALLOWLISTED": /* show allowlist instructions */ break;
case "USER_REJECTED": /* user declined in wallet */ break;
case "SIMULATION_FAILED": /* surface err.message */ break;
case "SEND_FAILED": /* retryable network/blockhash issue */ break;
default: /* UNKNOWN - surface err.message */
}
}
FunctionPurpose
executeDepositBorrowOne-call onboarding: init + deposit + borrow
executeActionManage an existing position: deposit / borrow / repay / withdraw
getPositionHeadless position read (collateral, debt, lender, vault)
getPositionMetricsDisplay-ready dashboard metrics - the exact values app.hobba.io renders
getQuoteProjection math for calculators and confirm modals
getLimitsInput bounds: max borrow / withdraw / repay, min deposit
parseCollateral, parseUsdc, format*Amount conversion
classifyErrorStable error codes
CBBTC_MINT, SOL_MINT, USDC_MINT, PROGRAM_ID, …Constants

Additional modules (PDAs, market config, IDL, oracle helpers) are importable by subpath - e.g. @hobba-io/core/pdas, @hobba-io/core/idl. The @hobba-io/core/rates subpath is server-only.