§9 · Building
Devnet quickstart
Get test xStocks, wrap them into a cohort and unwrap it again, without spending anything.
Devnet is Solana's free test network: its SOL has no value. The Cohort program is deployed there with four pods and ten mock xStocks. Nothing on this page costs money.
- Network
- Solana devnet · live
- Program
- 6uRisJz3Naz2cRmXmDWkCHtoGdNWnx6Hg42rxRy5aqeD
- Mock issuer
- EgtPNwuiNwBHLAWPfv6kdm36Ah2PMm7rji4eszXEp7ih
- Recorded
- 2026-11-06 07:57 UTC · deployments/devnet.json
The mock xStocks§
Each mock is a Token-2022 mint with 8 decimals, built with the same extensions as the mainnet xStocks: metadata, a permanent delegate, a default account state (new accounts start unfrozen), ScaledUiAmount with a multiplier of 1, Pausable, a confidential-transfer configuration, and a transfer hook with an authority but no program. Every authority on every mock, the freeze authority included, is one mock issuer key, which is on the devnet issuer allowlist. That key can do to a devnet pod whatever a real issuer could do to a mainnet one; it is how cHALT's vault came to be frozen.
The pods, their recipes and every address are listed on §4 The pods, read from deployments/devnet.json when these pages are built.
Two ways to try it§
Without a wallet. The app at /app can run in mock mode, in which wraps, unwraps and claim tickets are applied to local state in your browser with the program's own rounding. A "Mock data" banner under the header says when this is the case.
On devnet, with a wallet. When the app is built with its SDK client, it sends real devnet transactions to the program above. The steps below cover that path.
The faucet§
- Faucet code
scripts/devnet-faucet· not in the repository yet- Pays from
- EgtPNwuiNwBHLAWPfv6kdm36Ah2PMm7rji4eszXEp7ih
The faucet mints mock xStocks to a wallet. One drip gives:
- 5 shares of each of the ten mock xStocks;
- 1 cHALT, so you can try a partial unwrap straight away;
- 0.02 SOL if the wallet holds less than 0.01 SOL, because devnet's RPC airdrop is closed.
Each address can drip once every 6 hours, and a failed drip doesn't use up the slot. A drip is two transactions, signed and paid for by the mock issuer, which also creates any token accounts you are missing.
The faucet signs with the mock issuer's secret key, so it runs on Cohort's side, as a CLI or as a library for a server route:
# Operator CLI (needs the mock-issuer key)
cd scripts
npm run devnet:faucet -- <wallet-address> # the default drip
npm run devnet:faucet -- <wallet-address> --shares 0.5 --sol 0 --halt 0// Library, for a server route (Node.js runtime, not Edge)
import { dripTo, RateLimitError, InvalidAddressError, FaucetEmptyError } from "<repo>/scripts/devnet-faucet";
const res = await dripTo("<wallet address>");
// { address, signatures, minted: [{ symbol, mint, tokenAccount, amount }], solTopUpLamports, demoPodSent }dripTo checks the address before touching the network: it must be an on-curve wallet key, so PDAs are refused. Its errors map onto HTTP like this:
| Error | Status | When |
|---|---|---|
InvalidAddressError | 400 | not a base58 wallet key, or a PDA |
RangeError | 400 | an option out of range |
RateLimitError | 429 | the address dripped in the last 6 hours; retryAfterMs says how long to wait |
FaucetEmptyError | 503 | the faucet's own balance is below 0.05 SOL |
Options, all optional: amountPerStock (raw units, at most 1,000 shares), solTopUp (lamports), demoPodAmount (raw cHALT), and rateLimiter for a deployment with more than one server. The CLI exits 0 on success, 1 on a chain or RPC error, 2 on bad arguments and 3 when rate-limited.
Wrap and unwrap on devnet§
Set your wallet to devnet
In Phantom, Solflare or Backpack, switch the network to Devnet. You need a little SOL for fees and rent; the faucet tops up an empty wallet with 0.02 SOL, which covers several wraps.
Get mock xStocks
Take a drip from the faucet. The ten mock xStocks arrive in your associated token accounts, along with 1 cHALT.
Open a pod and wrap
Connect your wallet in the app, open a pod and choose Wrap. Enter how many cohorts to mint; the table shows exactly how much of each component you will deposit and the fee. Pick a slippage limit and sign. The pod mints the cohorts to you, minus the 30 bps fee.
Unwrap
Choose Unwrap, enter how many cohorts to return and sign. You get every component back pro-rata, minus the 30 bps fee taken in cohorts. The two fees and the rounding are the whole difference from what you deposited, as in the worked example in §2 How it works.
Try a partial unwrap
Open cHALT. The mock issuer has frozen its MSFTx vault, so wrapping is unavailable and the Unwrap button offers a partial unwrap: AAPLx now, a claim ticket for MSFTx. Sign it and find the ticket under Claims. It becomes redeemable if the vault is thawed. §6 Partial unwrap and claim tickets covers the details.
Run the burn
On a pod's page, the Distribute fees panel shows the cohorts waiting in its FeeVault. Anyone can send
distribute_fees; after it confirms, the backing per cohort is a little higher.