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

# TypeScript SDK

> Build bots, indexers, and frontends on hoodstar.fun with @hoodstar/sdk — typed reads and writes, exact quote math, and event streaming.

`@hoodstar/sdk` is the official TypeScript SDK for the hoodstar.fun protocol. It's a thin, fully-typed layer over [viem](https://viem.sh) — its only peer dependency — covering the entire protocol surface: launching tokens, trading the curve, quoting, migration, fee claims, and event streaming.

```bash theme={null}
npm install @hoodstar/sdk viem
```

<Info>
  The package is ESM-only. All amounts are `bigint` wei values — use viem's `parseEther` / `formatEther` helpers.
</Info>

## Setup

Create a viem client pair and pass it to `createHoodstar`. The SDK exports ready-made chain definitions for Robinhood Chain mainnet and testnet.

```ts theme={null}
import { createPublicClient, createWalletClient, http, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { createHoodstar, robinhoodMainnet } from "@hoodstar/sdk";

const publicClient = createPublicClient({
  chain: robinhoodMainnet,
  transport: http(),
});

const walletClient = createWalletClient({
  chain: robinhoodMainnet,
  transport: http(),
  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
});

const hood = createHoodstar({
  publicClient,
  walletClient, // optional — omit for read-only usage
  network: "mainnet", // or "testnet"
});
```

Three namespaces do all the work:

* `hood.read` — typed views over the launchpad (curve state, quotes, fees, registry, pool info)
* `hood.write` — transactions (throws if you didn't pass a `walletClient`)
* `hood.watch` / `hood.backfill` — event streaming and historical indexing

<Note>
  **Local development:** you can point the SDK at any deployment (e.g. an Anvil fork) by passing a deployment object instead of a network name:

  ```ts theme={null}
  const hood = createHoodstar({
    publicClient,
    walletClient,
    network: { chain, launchpad: "0x…", deployBlock: 0n },
  });
  ```
</Note>

## Reading the protocol

```ts theme={null}
// Enumerate tokens (newest last), then batch-fetch curve state in one RPC call
const tokens = await hood.read.getTokens(0n, 50n);
const states = await hood.read.getCurveStates(tokens);

// Per-token views
const info = await hood.read.getTokenInfo(tokens[0]);
// → { address, name, symbol, metadataURI }
const state = await hood.read.getCurveState(tokens[0]);
// → { virtualEth, virtualToken, realTokensLeft, realEth, creator, graduated, migrated }

// Protocol-wide fee config (live, in basis points)
const { protocolFeeBps, creatorFeeBps, totalFeeBps } = await hood.read.getFees();
```

## Quoting

You can quote **on-chain** (source of truth) or **client-side** — the SDK's `math` module is a bit-exact mirror of the contract's rounding, so quotes match to the wei with zero RPC round-trips:

```ts theme={null}
import { quoteBuy, quoteSell, currentPrice, curveProgressBps, ethToGraduate } from "@hoodstar/sdk";

const state = await hood.read.getCurveState(token);
const { totalFeeBps } = await hood.read.getFees();

// Instant, local, exact
const q = quoteBuy(state, totalFeeBps, parseEther("1"));
// → { tokensOut, fee, ethUsed, graduates }   graduates=true → this buy finishes the curve

const price = currentPrice(state);            // wei per whole token
const progress = curveProgressBps(state);     // 0–10000 (10000 = graduated)
const remaining = ethToGraduate(state, totalFeeBps); // gross ETH to buy out the curve

// Or ask the contract directly — identical results
const onchain = await hood.read.quoteBuy(token, parseEther("1"));
```

## Launching a token

`createToken` deploys the ERC-20 and opens its curve. Recover the token address from the `TokenCreated` event in the receipt:

```ts theme={null}
import { parseEventLogs } from "viem";
import { hoodLaunchpadAbi } from "@hoodstar/sdk";

const hash = await hood.write.createToken({
  name: "My Star",
  symbol: "MSTAR",
  metadataURI: "ipfs://Qm…",          // image + description, pinned to IPFS
  devBuyEth: parseEther("0.5"),       // optional first buy at the public price
});

const receipt = await publicClient.waitForTransactionReceipt({ hash });
const [created] = parseEventLogs({
  abi: hoodLaunchpadAbi,
  logs: receipt.logs,
  eventName: "TokenCreated",
});
const token = created.args.token;
```

<Note>
  Every `hood.write.*` method **simulates first** (so reverts are decoded before you spend gas) and returns the transaction `Hash` — await the receipt yourself with `publicClient.waitForTransactionReceipt`.
</Note>

## Trading

### Buying

```ts theme={null}
const ethIn = parseEther("1");
const q = quoteBuy(await hood.read.getCurveState(token), totalFeeBps, ethIn);

// Exact ETH in — slippage (default 1%) and deadline (default 5 min) built in
const hash = await hood.write.buy(token, ethIn, q.tokensOut, { slippageBps: 100 });
await publicClient.waitForTransactionReceipt({ hash });

// Or exact tokens out, refunding any excess ETH
await hood.write.buyExactTokens(token, tokensWanted, maxEthIn);
```

### Selling

Tokens support EIP-2612, so the one-transaction permit path is the default choice:

```ts theme={null}
const balance = await hood.read.balanceOf(token, account.address);
const sq = quoteSell(await hood.read.getCurveState(token), totalFeeBps, balance / 2n);

// One transaction: signs a permit, no separate approve needed
await hood.write.sellWithPermit(token, balance / 2n, sq.ethOut);

// Classic two-step path also available:
await hood.write.approve(token, amount);
await hood.write.sell(token, amount, sq.ethOut, { slippageBps: 50 });
```

## Graduation & migration

```ts theme={null}
const q = quoteBuy(state, totalFeeBps, parseEther("8"));
if (q.graduates) {
  // This buy will finish the curve; ethUsed < input and the remainder is refunded on-chain
}

// After graduation, anyone can migrate — permissionless and free
await publicClient.waitForTransactionReceipt({ hash: await hood.write.migrate(token) });

// Inspect the resulting Uniswap v3 pool
const pool = await hood.read.getPool(token);              // zero address until pool exists
const { sqrtPriceX96, liquidity } = await hood.read.getPoolState(pool);
const positionId = await hood.read.positionOf(token);     // locked LP NFT id (0 = not migrated)
```

## Claiming fees

```ts theme={null}
// Accrued but unclaimed creator fees for a token (in wei)
const owed = await hood.read.creatorFeesOwed(token);

// Claims are permissionless — funds always go to the registered recipient
await hood.write.claimCreatorFees(token);
await hood.write.claimProtocolFees(); // pays the treasury

// Harvest locked-LP swap fees for a graduated token (50/50 creator/treasury)
const locker = await hood.read.locker();
await hood.write.collectFees(locker, token);

// Redirect your creator fee stream (only the current recipient can call this)
await hood.write.setFeeRecipient(token, "0xNewRecipient…");
```

## Streaming events

The watch layer polls `eth_getLogs` over HTTP (Robinhood Chain's public RPC has no websocket), delivers events **at least once** in `(blockNumber, logIndex)` order, and gives you a cursor for crash-safe resumption:

```ts theme={null}
const stop = hood.watch(
  {
    onTokenCreated: (e) => console.log("new token", e.token, e.symbol, "by", e.creator),
    onTrade: (e) => console.log(e.token, e.isBuy ? "buy" : "sell", e.ethGross),
    onGraduated: (e) => console.log("graduated", e.token, "raised", e.ethRaised),
    onMigrated: (e) => console.log("pool live", e.pool, "position", e.tokenId),
    onBlockProcessed: (n) => saveCursor(n), // persist — resume point after restarts
    onError: (err) => console.error(err),
  },
  { fromBlock: await loadCursor(), pollIntervalMs: 1000 },
);

// later: stop()
```

For historical indexing, `backfill` replays the full event history in chunked `eth_getLogs` calls and resolves with the last processed block:

```ts theme={null}
const lastBlock = await hood.backfill({
  onTokenCreated: indexToken,
  onTrade: indexTrade,
});
```

<Info>
  Make handlers **idempotent** (delivery is at-least-once), and key trades on `transactionHash + logIndex` in your database.
</Info>

## Error handling

Writes simulate first, so contract reverts surface as decoded errors before gas is spent. The custom errors you'll most commonly handle:

| Error              | Meaning                                                  |
| ------------------ | -------------------------------------------------------- |
| `SlippageExceeded` | Curve moved past your `slippageBps` — re-quote and retry |
| `Expired`          | The `deadline` passed before inclusion                   |
| `CurveClosed`      | Token already graduated — trade it on Uniswap instead    |
| `CurveStillOpen`   | `migrate` called before graduation                       |
| `AlreadyMigrated`  | `migrate` called twice                                   |
| `UnknownToken`     | Address is not a hoodstar.fun launch                     |
| `ZeroAmount`       | Trade amount was zero                                    |
| `NotFeeRecipient`  | `setFeeRecipient` from a non-recipient address           |

## Full API surface

<AccordionGroup>
  <Accordion title="hood.read — all methods">
    `tokenCount()`, `getTokens(offset, limit)`, `getAllTokens()`, `getCurveState(token)`, `getCurveStates(tokens[])`, `getFees()`, `quoteBuy(token, ethIn)`, `quoteBuyExact(token, tokensOut)`, `quoteSell(token, amount)`, `creatorFeesOwed(token)`, `protocolFeesOwed()`, `feeRecipientOf(token)`, `getTokenInfo(token)`, `balanceOf(token, account)`, `getPool(token)`, `positionOf(token)`, `getPoolState(pool)`, `locker()`, `treasury()`, `weth()`, `positionManager()`
  </Accordion>

  <Accordion title="hood.write — all methods">
    `createToken({ name, symbol, metadataURI, devBuyEth?, minTokensOut? })`, `buy(token, ethIn, quotedTokensOut, opts?)`, `buyExactTokens(token, tokensOut, maxEthIn, opts?)`, `sell(token, amount, quotedEthOut, opts?)`, `sellWithPermit(token, amount, quotedEthOut, opts?)`, `approve(token, amount)`, `migrate(token)`, `claimCreatorFees(token)`, `claimProtocolFees()`, `setFeeRecipient(token, newRecipient)`, `collectFees(locker, token)` — trade `opts`: `{ slippageBps?: number; deadline?: bigint }`
  </Accordion>

  <Accordion title="Standalone math exports">
    `quoteBuy(state, totalFeeBps, grossIn)`, `quoteBuyExact(state, totalFeeBps, tokensOut)`, `quoteSell(state, totalFeeBps, amount)`, `currentPrice(state)`, `curveProgressBps(state)`, `ethToGraduate(state, totalFeeBps)`, `minAfterSlippage(quoted, slippageBps)` — plus constants `TOTAL_SUPPLY`, `SALE_SUPPLY`, `POOL_SUPPLY`, `VIRTUAL_TOKEN_0`
  </Accordion>

  <Accordion title="ABIs">
    `hoodLaunchpadAbi`, `hoodTokenAbi`, `feeLockerAbi` — exported for direct viem/wagmi use and event parsing.
  </Accordion>
</AccordionGroup>

<Card title="Contract reference" icon="file-contract" href="/developers/contracts">
  Prefer to integrate at the contract level? Full function, event, and error reference.
</Card>
