Skip to content

Search every page of the documentation, including the program reference and error codes.

↑ ↓ to move · Enter to open

Contents · §6 Partial unwrap and claims

§6 · Holding a cohort

Partial unwrap and claim tickets

When one component can't move, you can still take the others now and hold a ticket for the rest.

An unwrap normally pays every component in one transaction. If an issuer has paused one of them, or frozen the vault that holds it, that transfer would fail and take the whole unwrap with it. unwrap_partial avoids that: it pays everything that can move and writes the rest to claim tickets, which you redeem later.

When you can use it§

A component can go on a ticket only if, at the moment you unwrap, at least one of these is true:

  • its mint is paused;
  • the pod's vault for it is frozen;
  • your own token account for it is frozen;
  • its transfer-hook program is different from the one recorded when the pod was created.

Anything else must be paid out. Asking for a ticket on a component that can move fails with ComponentNotBlocked.

Walkthrough§

cHALT exists to try this. On devnet it holds AAPLx and MSFTx, and the mock issuer has frozen the pod's MSFTx vault; the faucet sends 1 cHALT to new wallets. The app's mock mode models cHALT differently, with TSLAx paused, and its Claims page has controls to pause and unpause it yourself.

  1. See which component is blocked

    Open the pod in the app. A blocked component is marked paused or frozen, and the Wrap tab says wrapping is unavailable: a wrap needs every component. The Unwrap tab switches to a partial unwrap on its own, and its button reads, for example, "Unwrap 1 of 2, ticket for MSFTx".

  2. Check the quote

    The quote is the same as a full unwrap's. The fee is taken in cohorts, the rest is burned, and each component's share is floor(net × tracked_balance ÷ supply). The blocked component's share is shown as "Claim ticket" instead of a transfer. Your slippage limit applies to the ticket amount too.

  3. Sign the partial unwrap

    The transaction calls unwrap_partial with a skip_mask (one bit per ticketed component) and a random nonce. It creates one ticket account per skipped component at the address ["claim", pod, you, component_index, nonce]. You pay the rent for each ticket, about 0.0017 SOL for its 122 bytes, and get it back when you redeem.

  4. What changes on-chain

    The movable components arrive in your wallet. For each ticketed one, the program moves your share out of the pod's tracked_balance and into claims_outstanding. The tokens stay in the vault, reserved for you, and stop counting as backing for the remaining cohorts. Your cohorts are burned exactly as in a full unwrap.

  5. Wait for the component to move

    The ticket appears under Claims in the app, marked redeemable or not. The SDK's listClaims(owner) reports the same thing from the live mint and token accounts: a ticket is redeemable when the mint isn't paused and neither the vault nor your account is frozen.

  6. Redeem

    redeem_claim transfers the ticket's exact raw amount to your token account, lowers claims_outstanding by the same amount and closes the ticket, returning its rent to you. If the component still can't move, the transfer fails and the ticket stays open, unchanged, for another try.

What a ticket is, and isn't§

  • A fixed amount. It records raw units at the moment you unwrapped. Later fee burns raise the backing of cohorts, not of tickets.
  • Yours alone. Only the owner recorded in the ticket can redeem it, and there is no instruction to transfer it.
  • Protected first. A later seizure is charged to the pod's tracked balance before it can reach reserved claim tokens. Only a seizure larger than everything the pod tracks for that component could leave a ticket short.
  • Not guaranteed to pay soon. It pays when the issuer lets the token move. Cohort has no way to make that happen.

From the SDK§

TypeScript
import { createCohortClient } from "@cohort/sdk";

const client = createCohortClient(connection);
const pod = await client.getPod(podAddress);
const skip = pod.components.filter((c) => c.paused || c.frozen).map((c) => c.index);

const tx = await client.buildUnwrapPartialTx({
  pod: podAddress,
  user: wallet.publicKey.toBase58(),
  podAmount: 2_000_000_000n, // 2 cohorts
  slippageBps: 50,
  skip,
});
await wallet.sendTransaction(tx, connection);

// Later, once the component moves again:
for (const t of await client.listClaims(owner)) {
  if (t.redeemable) await wallet.sendTransaction(await client.buildRedeemClaimTx(t.address, owner), connection);
}

buildUnwrapPartialTx throws if skip is empty; use buildUnwrapTx then. ComponentView.frozen reports the pod's vault; a frozen account of your own also qualifies, so check it if a plain unwrap fails. More in §8 The TypeScript SDK.

Before you continue

Not available to US persons or in restricted regions.

Cohort is experimental software on Solana devnet. Cohort tokens are backed by tokenized stocks issued by third parties, who can freeze, pause or seize them.

You may not use this interface if you are a resident of, or located in:

  • the United States and its territories
  • Canada
  • the United Kingdom
  • Australia
  • any country or region subject to comprehensive sanctions (including Cuba, Iran, North Korea, Syria, and the Crimea, Donetsk and Luhansk regions)
Terms v2026-11-06