> ## Documentation Index
> Fetch the complete documentation index at: https://docs.star.fun/llms.txt
> Use this file to discover all available pages before exploring further.

# Presale SDK

> Add precommit and deposit buttons to your website.

Use this SDK to add **Precommit** and **Deposit** buttons to your website. Connect the user's Solana wallet, then use the examples below.

Only need to show totals and dates? Use the [display guide](/developers/fundraise-api); no SDK required.

## Install

```bash theme={null}
pnpm add @starfun/sdk-vault@2.0.5 @solana/web3.js@^1 @solana/spl-token@^0.4 bn.js
pnpm add -D @types/bn.js
```

## Set up

The examples use a connected `wallet` with `publicKey` and `signTransaction`.

```ts theme={null}
import BN from 'bn.js';
import { Connection, PublicKey, Transaction } from '@solana/web3.js';
import { getMint } from '@solana/spl-token';
import {
  StarVault,
  buildLockCommitmentTx,
  buildWithdrawCommitmentTx,
  fetchCommitmentRecord,
  getVaultStatusKey,
} from '@starfun/sdk-vault';

const connection = new Connection(RPC_URL, 'confirmed');
const vaultAddress = new PublicKey(VAULT_ADDRESS);
const programId = new PublicKey(VAULT_PROGRAM_ID);
const vault = await StarVault.create(connection, vaultAddress, programId);
const quoteMint = new PublicKey(vault.account.quoteMint);
const quoteTokenProgramId = new PublicKey(vault.account.quoteTokenProgram);
const mint = await getMint(connection, quoteMint, 'confirmed', quoteTokenProgramId);

async function send(tx: Transaction) {
  const latest = await connection.getLatestBlockhash('confirmed');
  tx.feePayer = wallet.publicKey;
  tx.recentBlockhash = latest.blockhash;
  const signed = await wallet.signTransaction(tx);
  const signature = await connection.sendRawTransaction(signed.serialize());
  console.log('Submitted:', signature); // Save this receipt before waiting.
  const result = await connection.confirmTransaction({ signature, ...latest }, 'confirmed');
  if (result.value.err) throw new Error(`Transaction failed: ${signature}`);
  return signature;
}
```

Amounts use quote-token base units: for a six-decimal mint, 25 tokens is `new BN('25000000')`. Read `mint.decimals`; keep amounts as decimal strings or `BN`, never floating-point numbers. Users also need SOL for transaction fees and account rent.

## Precommit

Refresh the vault before showing an action. Precommits lock funds until conversion or cancellation; users cannot withdraw at will.

```ts theme={null}
await vault.fetch();
if (getVaultStatusKey(vault.account.status) !== 'precommitActive') {
  throw new Error('Precommit is not open');
}
const signature = await send(
  await buildLockCommitmentTx(
    connection,
    {
      user: wallet.publicKey,
      vault: vaultAddress,
      quoteMint,
      quoteTokenProgramId,
      amount: new BN('25000000'), // 25 tokens ONLY for a six-decimal mint.
      ensureAta: true,
      wrapWsol: true,
    },
    programId,
  ),
);
```

Conversion into a deposit is a separate transaction after the live raise starts. Star or your integration operator submits it using `buildConvertCommitmentTx`.

## Deposit during the live raise

```ts theme={null}
await vault.fetch();
if (getVaultStatusKey(vault.account.status) !== 'active') {
  throw new Error('Presale is not active');
}
const signature = await send(
  await vault.deposit(
    new BN('25000000'), // 25 tokens ONLY for a six-decimal mint.
    wallet.publicKey,
    { quoteTokenProgramId, ensureAtas: true, wrapWsol: true },
  ),
);
```

Also check the [start and end times](/developers/fundraise-api) when displaying the deposit button. The program enforces the live window. For SOL raises, automatic wrapping requires the atom amount to fit within `Number.MAX_SAFE_INTEGER`.

Read positions with `fetchCommitmentRecord(connection, vaultAddress, wallet.publicKey, programId)` and `StarVault.fetchDepositorRecord(...)` using the same arguments. Their `null` result can mean a missing account or a read error.

## Withdrawals and refunds

An unconverted commitment is withdrawable **only after cancellation**:

```ts theme={null}
await vault.fetch();
const commitment = await fetchCommitmentRecord(
  connection,
  vaultAddress,
  wallet.publicKey,
  programId,
);
if (getVaultStatusKey(vault.account.status) !== 'cancelled' || !commitment) {
  throw new Error('Cancelled commitment required');
}
const remaining = commitment.lockedAmount
  .sub(commitment.withdrawnAmount)
  .sub(commitment.convertedAmount);
if (commitment.converted || remaining.lte(new BN(0))) throw new Error('Nothing to withdraw');
await send(
  await buildWithdrawCommitmentTx(
    connection,
    {
      user: wallet.publicKey,
      vault: vaultAddress,
      quoteMint,
      quoteTokenProgramId,
      amount: remaining,
      ensureAta: true,
    },
    programId,
  ),
);
```

For eligible cancelled or failed deposits, use `claimRefund`. After accepted launch allocation, use `claimExcessRefund` for unclaimed excess:

```ts theme={null}
const refundDeposit = async () =>
  send(await vault.claimRefund(wallet.publicKey, { tokenProgramId: quoteTokenProgramId }));
const refundExcess = async () =>
  send(await vault.claimExcessRefund(wallet.publicKey, { tokenProgramId: quoteTokenProgramId }));
```

These return quote tokens. Project-token claims use a separate launchpad integration or the project's claim link on Star.

Disable repeat submissions while signing/sending. Refresh the position and [fundraise totals](/developers/fundraise-api) after confirmation. If confirmation times out, check the saved signature before submitting another contribution. Test the package in your production browser bundle; its CommonJS dependencies may require bundler configuration.
