# bskts documentation

> bskts are fixed-quantity index tokens on Robinhood Chain (an Arbitrum Orbit L2,
> chain id 4663). Each basket is an ERC-20 whose supply is a proportional claim on
> a fixed set of Stock Tokens and crypto held in an on-chain vault. Buy and redeem
> at net asset value (NAV), from your own bskts account with the gas paid for you,
> or from a connected wallet. The protocol never custodies your funds.
>
> The markdown copy of https://bskts.xyz/docs, for agents. To trade through the
> API, read https://api.bskts.xyz/llms.txt instead.

## Overview

Every basket bundles a fixed quantity of each constituent per unit. Hold one unit
of DIGI64 and you hold a fixed amount of the S&P 500 token and of ETH, not a
re-weighted slice that changes underneath you. Weights drift as prices move;
scheduled rebalances restore targets.

bskts is non-custodial by construction. Buying swaps USDG into the exact
constituents and deposits them; redeeming returns the constituents (or swaps them
back). The contract holding your assets never touches a DEX, and you can always
exit in kind.

Core pieces: the **Vault** holds the assets and is the index token; the **Zapper**
converts USDG to and from the basket; the **NavOracle** prices everything from
on-chain pools. A **bskts account** (a Safe only you control) holds your USDG and
baskets and trades without a popup per trade. Resting orders sit in ownerless
escrow contracts that anyone may fill under price floors you set.

## Getting started

1. Log in with email, Google, X, GitHub, a passkey or an existing wallet. A wallet
   is created for you if you don't bring one.
2. Create your account: one signature deploys your bskts account (a Safe owned by
   your login wallet) and sets up instant trading in this browser. bskts pays the gas.
3. Add funds: USDG on Robinhood Chain, USDC bridged from Base, Arbitrum, Optimism
   or Ethereum, or a card.
4. Buy a basket from any market page. It fills in seconds with no wallet popup.

You can also trade from a connected wallet on Robinhood Chain; you then sign each
transaction and pay its gas in ETH yourself. Agents and bots use the API
(https://api.bskts.xyz/llms.txt) and sign with their own wallet.

## Accounts & gasless trading

Your bskts account is a Safe deployed for your login wallet by the AccountFactory.
Your wallet is its only owner: only you can withdraw, and you can withdraw
everything at any time, with or without bskts. Withdrawing through bskts is
gasless and costs a flat $1, taken from the amount; basket units pay the same $1
in USDG. Withdrawing directly from your Safe costs only your own gas.

**Instant trading (session keys).** Creating the account installs a session key
that lives only in that browser. The BsktsSessionModule lets it buy, sell, place
and cancel limit and exit orders, and stop a recurring buy, and nothing else: it
can never withdraw or send funds anywhere. It expires after
30 days (renewed with one signature), every trade is capped
at 3.00% slippage, daily volume is capped, and
you can revoke it.

**Gasless, with a network fee in USDG.** Account trades are relayed: bskts submits
them and pays the gas in ETH, and each trade adds its own gas, priced in USDG from
the WETH/USDG pool, to the same transaction (shown before you confirm). Account
trades have a $5 minimum (selling a whole position can be
smaller). The relayer can only submit what you or your session key signed.

## How NAV works

NAV per unit is the value of what a unit owns:

    navPerShare = Σ ( vault.balanceOf(assetᵢ) × priceᵢ ) / totalSupply

Prices come from the NavOracle, which prices every asset, ETH included, from its
own Uniswap pools on Robinhood Chain, never from an external feed. Each asset's
feed reads its deepest pool and cross-checks a second venue; if they disagree
beyond a tolerance, or a pool is empty, the read reverts, so a basket can never
mint against a bad price. Resting orders trigger on a **reference NAV**: each
constituent's price averaged over the last 10 minutes of its pool, which no
single transaction can move. One kind of pool keeps no history to average
(Uniswap v4), so a token whose deep pool is a v4 pool is read at that pool's
live price instead; today that is NVDAx3L, held only by TURBO.

Dividends accrue automatically: Robinhood's Stock Tokens carry ERC-8056
total-return accrual, so dividends flow into the token's value and into NAV.

**Why deposits can't move the price.** Minting and redeeming are proportional and
in kind, so no deposit or withdrawal of any size changes NAV per share. Rounding
favours the vault (previewMint rounds up, previewRedeem rounds down), and the first
mint burns a MIN_LIQUIDITY dead-share floor against the first-depositor attack.
Only three things move NAV per share: constituent prices, the streaming
management fee, and rebalance costs.

**Rebalances.** On each basket's schedule (monthly or quarterly) a rebalancer swaps
constituent for constituent toward target weights, constrained on-chain: only an
allowlisted router, both sides of every swap must be constituents, the oracle must
be live, and NAV after must be within maxRebalanceLossBps of NAV before or the
transaction reverts. A rebalance can rearrange what a basket holds; it cannot
spend it.

## The baskets

| Ticker | Name | Constituents (target weight) | Rebalance | Mgmt fee |
|---|---|---|---|---|
| DIGI64 | Digital 60/40 | SPY 60%, ETH 40% | monthly | 0.65%/yr |
| MAG6 | Mega-cap Tech | NVDA 17%, AAPL 17%, MSFT 17%, GOOGL 17%, META 17%, TSLA 17% | quarterly | 0.75%/yr |
| INDEX2 | Broad Beta | SPY 50%, QQQ 50% | quarterly | 0.50%/yr |
| FRONTIER | Moonshot Growth | SPCX 33%, TSLA 33%, NVDA 33% | quarterly | 0.95%/yr |
| CRYPTOEQ | Crypto Complex | COIN 25%, MSTR 25%, CRCL 25%, ETH 25% | monthly | 0.95%/yr |
| OPUS | AI Core | NVDA 50%, MSFT 30%, GOOGL 20% | quarterly | 0.85%/yr |
| FABLE | AI Capex | MU 30%, TSM 25%, AMD 20%, INTC 15%, SNDK 10% | quarterly | 0.75%/yr |
| ORBIT | BTC, Space & Nasdaq | cbBTC 33%, SPCX 33%, QQQ 33% | quarterly | 0.95%/yr |
| MAXBETA | High-Volatility Four | TSLA 25%, MSTR 25%, COIN 25%, SPCX 25% | quarterly | 0.85%/yr |
| SILICON | Chipmaker Trio | NVDA 33%, AMD 33%, TSM 33% | quarterly | 0.75%/yr |
| ETHSTACK | Ethereum Economy | ETH 50%, COIN 25%, CRCL 25% | monthly | 0.75%/yr |
| NATIVE | Robinhood Originals | PONS 25%, UP 25%, ETH 25%, cbBTC 25% | monthly | 0.95%/yr |
| HARD | Hard Assets | GLD 50%, cbBTC 25%, SLV 15%, USO 10% | monthly | 0.75%/yr |
| BEDROCK | All Weather | SPY 34%, SGOV 33%, GLD 33% | monthly | 0.50%/yr |
| TURBO | Leveraged Tech | NVDAx3L 40%, MSTR 30%, SPCX 30% | monthly | 0.95%/yr |

Weights are targets; live weights drift with price between rebalances.

**Higher-risk baskets.** NATIVE: Holds Robinhood Chain’s own native tokens rather than Stock Tokens. Two have no published price feed — they’re valued from their own liquidity pools — so expect thinner liquidity and wider spreads than a common basket. TURBO: Holds NVDAx3L, a daily-reset 3x leveraged NVIDIA token issued by Lighter × Long. Its issuer can pause or upgrade it with a single key, and a pause would block every TURBO sell and redemption — including the MSTR and SPCX legs — until it is lifted. Leveraged tokens also lose value in choppy markets. Size positions accordingly.

**BSKTS** is a basket of baskets: an index vault whose constituents are other
baskets' shares. It prices and redeems the same way; in kind, it returns the
basket shares it holds.

## Buying & swapping

Buy with USDG. The Zapper routes it through each constituent's deepest Uniswap
pool into the exact quantities the vault needs, then mints your units. It takes
the mint fee (0.20%) off the top and sweeps any dust back to you.
Your protection is a minimum number of units you agree to before signing,
enforced on-chain. From an account there is nothing to approve; from a connected
wallet the first USDG buy needs an approval. Swap (https://bskts.xyz/swap) buys
and sells any basket against USDG and switches between baskets in one step.

## Deposits & wallets

Every deposit ends up in your bskts account (its address is under Cash on your
portfolio). Your login wallet is the account's owner, a key rather than a place to
keep money. You can send from any wallet.

- USDG from your login wallet: one signature, no fee, bskts pays the gas.
- USDG from another wallet: a plain transfer; that wallet pays Robinhood Chain gas in ETH.
- USDC from Base, Arbitrum, Optimism or Ethereum: bridged by Across (about 0.25%,
  quoted live) and delivered as USDG, usually within seconds; refunded if Across
  can't fill.
- Card or Apple Pay (email and social logins): USDC bought on Base through Stripe
  or MoonPay, then bridged in.
- From an exchange: withdraw USDG on Robinhood Chain to your account address. Send
  nothing else, and no other network.

Your account belongs to the wallet you first logged in with; adding another login
method later never changes the owner. Cross-chain buys straight from a wallet
through the IntentEscrow closed to new orders on 2026-09-29; any unfilled intent
stays withdrawable by its owner.

## Orders

Resting orders are held by ownerless contracts. Anyone may fill a triggered order
for a small fee, so none depends on bskts staying online, but only at or better
than a floor you agreed to.

- **Limit buy** (LimitEscrow): your USDG is escrowed and fills when NAV reaches
  your trigger (none = market). The floor is priced at fill time from the better
  of spot and the reference NAV, opening near the basket's quoted cost and easing, only
  while nobody can fill, to at most 3.00%. Withdraw it any time before it fills.
- **TWAP and Recurring** (SpendPermitManagerV4): a fixed buy each period, capped
  in total and per period. The USDG stays in your account or wallet until each buy.
- **Stop-loss, take-profit, brackets** (SellEscrowV4): shares are escrowed and
  sold to USDG when the reference NAV crosses your level (a bracket is
  one-cancels-the-other). The sale must return at least NAV less the basket's
  quoted trading cost plus 0.45% (0.5% at the least), easing toward 3% only while
  nobody can fill. Cancel any time.

Orders are unavailable for a basket holding a token with no pool price history
yet (today TURBO).

## Redemption

Redemption is always open, can never be paused, and never reads the oracle, so you
can exit even while prices are frozen.

- **In kind**: receive every constituent token, proportional to your units. Free.
- **Sell to USDG**: the Zapper sells each constituent to USDG in one step, net of
  the zap-out fee (0.20%) and slippage.

## Fees

| Fee | Amount | When |
|---|---|---|
| Mint | 0.20% | Off the top when you buy, to the treasury |
| Zap-out | 0.20% | On the proceeds when you sell to USDG, to the treasury. In-kind redemption is free |
| Management | 0.50%–0.95%/yr | Per basket, streamed as newly minted shares to the treasury |
| Filler fee | max($0.25, 0.15%), at most 1% | On resting orders and scheduled buys, to whoever executes them |
| Network fee | gas, in USDG | On account trades: that trade's own gas |
| Withdrawal | $1 | Per withdrawal from a bskts account through bskts, to the relayer that pays accounts' gas |
| Bridge | ~0.25% | Across's fee on cross-chain deposits |

Mint, zap-out, management and network fees go to the bskts treasury. None is
paid back to holders.

## Architecture

- **BasketFactory**: deploys vaults and owns the NavOracle; constituents are
  registered and pinned by address, never resolved by symbol.
- **BasketVault**: the ERC-20 index token and custody core; only in-kind mint and redeem.
- **Zapper and Router**: USDG to and from a basket through pinned pools, with
  per-leg token checks.
- **NavOracle, PoolPriceFeeds, PoolPrices**: pool-derived spot prices
  (cross-checked) and the reference prices for order triggers and floors
  (10-minute pool averages; a live pool price for a v4-only token). Orders and
  accounts read them through the PriceRouter.
- **LimitEscrow, SellEscrowV4, SpendPermitManagerV4**: ownerless order contracts;
  anyone may execute, floors enforced on-chain.
- **AccountFactory, BsktsSessionModule**: the Safe account and its browser-only trading keys.
- **IndexVault, IndexZapper**: BSKTS. **BasketSwapRouter**: switches between baskets.

Off-chain, a relayer submits accounts' signed transactions and pays their gas, and
a keeper indexes orders and fills triggered ones (as anyone may). Neither can move
funds.

## Security model

- Solvency by rounding: redeeming the whole supply can never exceed the vault's balances.
- Unconditional exit: redeem never reads the oracle and has no pause.
- Pool prices only: no external price feed anywhere; orders trigger on a
  10-minute average no single transaction can move.
- Your account, your keys: only your wallet can withdraw; session keys only trade,
  within expiry, slippage and daily caps.
- Ownerless order contracts: no admin, no pause, no upgrade path; every fill held
  to your floor.
- Segregated liability: a fill takes exactly one order's escrowed amount.
- Inflation-attack floor: the first mint burns dead shares.
- Address-pinned constituents: impostor tokens share real symbols on-chain, so
  every asset is referenced by address only.

## Contract addresses

Robinhood Chain (id 4663). Every contract is exact-match verified on Sourcify
(https://repo.sourcify.dev/4663/<address>). Explorer: https://robinhoodchain.blockscout.com

Core:
- BasketFactory: `0xb7c27E044E8Acc8aB3f091a2F9d424A32723e4c3`
- ZapperV2: `0xC12d7D93ee0dD10D5b890EE1250045BBAfFBe627`
- RouterV2: `0x00F539192E54cdfaA9fE554CB7D1B66568dDbC68`
- BasketSwapRouter: `0xD7Da7F25384b5f03f5BBFDf12472D2709D18a0EC`
- USDG: `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168`

Orders:
- LimitEscrow: `0x5e267dBD5d0540be1b6EADe920F288fF50EB76Db`
- SellEscrowV4: `0x7e0B140162ed713398842e25e18c7371230669e0`
- SpendPermitManagerV4: `0x7fd0476f5ab559Ae967a7F1c9F6059b449acc28E`
- PriceRouter: `0x25975A83dee2b342f33C270C04556bEf19408533`
- PoolPrices: `0x6611e0e4A56B4c68224016E11F148f36257eC551`
- IntentEscrow: `0x2Ec37EEC88fEfEDd4691e4492c626EB0980F8A54`

Accounts:
- AccountFactory: `0xd9424BcFD33fBEF67019b736672626D7DAB954A3`
- BsktsSessionModule: `0x66a0ba9be3f6779b4f24CE6135Cc93B5559888Da`

Basket vaults:
- BSKTS (index vault): `0xa71AAf7E54Bd27140FE6eb25e008dAF31E2Ffe3D`
- IndexZapper: `0x791BDBec0a70b502B4e0A1Afe992D95898743c3a`
- DIGI64: `0x63e5dFBEC475b3afA031be9031e73aCdb6F1d559`
- MAG6: `0x6A19EcdA657209659c019eb629A2d4718a1af6d9`
- INDEX2: `0xC02b7A59846B77d0b1d0cfE8943D32c279ED292a`
- FRONTIER: `0x9c0DD188E9Bf1cB0F9495a76482e73745F704ac5`
- CRYPTOEQ: `0x4Ef22a6B9c14255f21B06463c28742166dC4308E`
- OPUS: `0x8E67148C7682C2f0485F6C3012EAf877D6b54A93`
- FABLE: `0xE5548Cb2A94F65B3B9953E582B4F8fD47d15A439`
- ORBIT: `0x20D6C400DBCF0cCcC08C408c244A3D4fd85275C4`
- MAXBETA: `0x25c5aD70B522dB7dcE405801230508868C15452A`
- SILICON: `0x421caF01904d2113379c7AC82975d067993b0a95`
- ETHSTACK: `0xD0794356c6Bf6DC67aCcB321FDC53761517F45eE`
- NATIVE: `0x64371Dc3D699dC798B3775460Bf39162aECb01bD`
- HARD: `0xE1932EB91a4306135CaB523678D18Dd07D702EE6`
- BEDROCK: `0xB84DA24d66783b031907dC8749Afec71990f2FAb`
- TURBO: `0xD6732405722687Dd977A45Fd57dB43491946012e`

Earlier versions (existing orders can still be cancelled; the API's buys and
sells still use Zapper v1):
- Zapper (v1): `0x81f275D289f8cbD0B5d5Efc5289F2933998E7D8e`
- Router (v1): `0x79A8CF0e95568B011D6e9bE706C288416295ED78`
- SellEscrowV3: `0x4F5fe598F454fCF3104678CC958186D9e54f8864`
- SellEscrowV2: `0x35B42F515062BE2E79eC49F3DaE071E1c1fc1BCB`
- SellEscrow: `0x1F986683Af494f293Cf02d7cAED851215077e115`
- SpendPermitManagerV3: `0x4149C2CeF5F9181249e93547368f5B292973Ba65`
- SpendPermitManager: `0x1Dbaa48A7cCC6bB71bB344eB39d9c632E0F38a00`

## Developers & agents

Everything you can trade in the app is open to code and AI agents, through an
MCP server, a TypeScript SDK and a REST API. All three follow one rule: nothing is
ever signed or sent for you. They read markets and accounts and prepare
transactions; your wallet signs each one.

**Connect an AI agent (MCP).** bskts runs an MCP server at
https://api.bskts.xyz/mcp (Streamable HTTP, no key, no account). Claude Code:
`claude mcp add --transport http bskts https://api.bskts.xyz/mcp`. Claude
(desktop and web): Settings → Connectors → Add custom connector. ChatGPT: on plans
with Developer mode, add a custom connector with the URL and no authentication.
Cursor and others: `{ "mcpServers": { "bskts": { "url": "https://api.bskts.xyz/mcp" } } }`.
To set your own limits, run it locally: `npx -y @bskts/mcp` with
BSKTS_MAX_USD_PER_TRADE and BSKTS_ALLOWED_TICKERS. Tools: bskts_markets,
bskts_basket, bskts_account, bskts_buy, bskts_sell, bskts_order, bskts_guide. A
prepared trade is an optional approval, then the trade, with a dry run from your
address: sign the approval first, and never send one whose dry run failed. These
wallet tools trade from a regular wallet and pay gas in ETH; an agent trading from
a bskts account (below) needs no ETH, and network fees come out of account USDG.

**Agents with a shell: the bskts skill.** OpenClaw, Hermes, Claude Code and other
agents that can run commands can use
https://github.com/Tokenise-au/bskts-sdk/tree/main/skills/bskts: a SKILL.md and a
small signer that keeps the agent's own key on its machine. The Agents tab gives
the owner one message to paste, with their wallet filled in; the agent installs
the skill and returns its approval link. Trades are dry runs unless --send, and
each live trade is journalled by ID so a retry never sends it twice.

**TypeScript SDK.** `npm i @bskts/sdk viem`: a typed client (responses checked
against schemas, amounts as bigints, a dry-run guard, optional limits) that signs
through viem. Errors carry a stable code. Source, reference and the MCP server:
https://github.com/Tokenise-au/bskts-sdk

**REST API.** A public, keyless, non-custodial API at https://api.bskts.xyz:
reads return market and account data, and /v1/tx/* return unsigned transactions
({ approval, tx, simulation }) you sign with your own wallet. Send the approval
and wait for it before the tx; simulation.ok false means it would revert. Dollars
are plain numbers, on-chain amounts are integer strings in base units (shares 1e18,
USDG 1e6). Errors are { error, code, retryable }.

**Autonomous account agents (new, in testing).** Create the signing key in your
host wallet or secure signer and share only its public address. The owner connects
it at https://bskts.xyz/portfolio?tab=agents and signs permissions: suggested 10% of
available account USDG (at least $10) capped at $100/day, 0.5% maximum slippage,
7 days. The dollar
cap stays fixed after deposits; only the owner can change or renew it. Approval
sets up the current account modules if needed, with the same account and holdings.
GET /v1/agent/session?owner=&key= reports live authority, moduleEnabled and
coverEnabled. POST /v1/agent/trade builds an unsigned buy/sell Action; the host
signs it and uses https://bskts.xyz/relay/v1/account/execute. No owner popup per
trade or owner/agent ETH is needed. SDK: agentSession, buildAgentTrade,
executeSession, sessionRelayer. MCP: bskts_agent_session, bskts_agent_trade (unsigned).
SDK 0.5.0+ also provides executeSessionOnce and sessionActionState. Persist each
unsigned plan in an exclusive durable store before signing; retain the journal
and outcome, even after success. Restarting reconciles the original nonce and
never submits that operation again. Node hosts can import fileSessionStore
from @bskts/sdk/node; independent hosts need a shared store. Do not journal keys
or signatures, or replace an unresolved operation with a new journal ID.
Never send a private key to the API, MCP or dashboard. Start with a small allowance.
Daily basket turnover counts buys and sells, resets at 00:00 UTC, is per key and
excludes network fees; the host must set an explicit fee cap. Agents can also BUY
Weekend Cover on baskets the account holds once the owner has enabled Cover: GET
/v1/cover/weeks, /v1/cover/book/{ticker} and /v1/cover/positions/{account} read
it, POST /v1/agent/cover builds an unsigned take, request or cancel for the same
key (SDK buildAgentCover / executeCover; MCP bskts_agent_cover). Cover spending is
counted separately against the same daily limit, at most 3% of the cover per
purchase. Agent tools never underwrite: that needs the owner's own allowance. Revoking a key
blocks new basket/Cover requests; existing basket orders, schedules and Cover
listings need separate cancellation in Portfolio and My cover. Reconnect with a
fresh key. Keep the same nonce/trade on bounded 402 fee retries; after an uncertain
submission check nonceUsed and execution logs before resubmitting.

- Trading guide for agents (the loop, units, errors): https://api.bskts.xyz/llms.txt
- OpenAPI: https://api.bskts.xyz/openapi.json

**Earn fees by executing orders.** Triggered resting orders and due scheduled buys
are public jobs: anyone may execute one for its fee, max($0.25, 0.15%) up to 1%.
GET /v1/jobs lists them with calldata; each fill is held to its on-chain floor.

**Building on basket tokens.** A share is an ordinary ERC-20 that anyone can
redeem in kind at any time, and whose price is readable on-chain:
navPerShareE18() computes it from the vault's balances and pool prices. Price a
share from NAV, never from a thin share/USDG pool. Liquidation needs no share
market: redeem in kind and sell each constituent into its own pool
(/v1/leverage/sell-routes returns those swaps). navPerShareE18() reverts while a
price read fails; in-kind redeem keeps working. Stock Tokens trade around the
clock but follow equity market hours, so overnight and weekend gaps are real.
