§7 · Building
Program reference
Every instruction, account, event and error in the Cohort program, generated from its IDL at build time.
- Program
6uRisJz3Naz2cRmXmDWkCHtoGdNWnx6Hg42rxRy5aqeD(declare_id; see the devnet page for deployments)- IDL
sdk/src/idl/cohort.json· cohort 0.1.0 · Anchor 0.29- IDL sha256
fe30587d044e0a99…
This page is generated by scripts/docs-build.mjs before every build: accounts, arguments, layouts and error codes come straight from the IDL. The summaries and invariants are notes checked against the IDL by a test, so an instruction or error the program gains without a note fails npm test. Amounts are raw base units; cohorts have 9 decimals. For the reasoning behind the rules, read §2 How it works first.
Instructions
14 instructions: initialize_config, set_wraps_paused, add_issuer, remove_issuer, set_pod_verified, create_pod, wrap, unwrap, unwrap_partial, redeem_claim, distribute_fees, reconcile, set_creator_share, set_lookup_table.
initialize_configSDK: initializeConfig
Creates the one ProtocolConfig account: admin, treasury and the protocol's share of fees for pods created afterwards.
Signer · The program's upgrade authority, once. The program and programData accounts prove it, so nobody can front-run the initialisation.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | payer | mutsigner | Must be the program's upgrade authority (prevents front-running the init). |
| 1 | config | mut | |
| 2 | program | ||
| 3 | program_data | ||
| 4 | system_program |
Arguments
| Argument | Type |
|---|---|
admin | Pubkey |
treasury | Pubkey |
protocol_share_bps | u16 |
Checks and invariants
- protocol_share_bps ≤ 5,000.
- max_components is set to 10 and wraps_paused to false.
Program errors
set_wraps_pausedSDK: setWrapsPaused
Blocks or unblocks new wraps and new pods, protocol-wide.
Signer · config.admin.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | admin | signer | |
| 1 | config | mut |
Arguments
| Argument | Type |
|---|---|
paused | bool |
Checks and invariants
- Has no effect on unwrap, unwrap_partial or redeem_claim. Those instructions don't take the config account at all.
Program errors
add_issuerSDK: addIssuer
Adds a key (a freeze authority, permanent delegate, pause authority, transfer-hook authority or hook program) to the issuer allowlist.
Signer · config.admin, who pays rent for the new account.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | admin | mutsigner | |
| 1 | config | ||
| 2 | issuer | mut | |
| 3 | system_program |
Arguments
| Argument | Type |
|---|---|
key | Pubkey |
label | string |
Checks and invariants
- label is at most 32 bytes.
- One account per key: adding the same key twice fails at account creation.
Program errors
remove_issuerSDK: removeIssuer
Closes an allowlist entry and returns its rent to the admin.
Signer · config.admin.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | admin | mutsigner | |
| 1 | config | ||
| 2 | issuer | mut |
Arguments
None.
Checks and invariants
- Only future create_pod calls are affected. Existing pods keep working, and unwraps never consult the allowlist.
Program errors
set_pod_verifiedSDK: setPodVerified
Sets or clears a pod's verified flag.
Signer · config.admin.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | admin | signer | |
| 1 | config | ||
| 2 | pod | mut |
Arguments
| Argument | Type |
|---|---|
verified | bool |
Checks and invariants
- A curation label only. It changes nothing about how the pod wraps, unwraps or pays fees.
Program errors
create_podSDK: createPod
Creates a pod: validates every component mint, creates the clean Token-2022 pod mint and its vaults, and performs the fee-free genesis wrap.
Signer · Anyone (the creator). The pod mint is a fresh keypair that signs.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | creator | mutsigner | |
| 1 | config | mut | |
| 2 | pod | mut | |
| 3 | pod_mint | mutsigner | New Token-2022 mint keypair; created and initialised here. |
| 4 | fee_vault | mut | |
| 5 | creator_pod_account | mut | |
| 6 | pod_token_program | ||
| 7 | associated_token_program | ||
| 8 | system_program |
Remaining accounts
- Per component, 4 accounts: mint, vault (the pod's associated token account for that mint), creator's source token account, token program.
- Then transfer-hook extra accounts, hook_extras[i] of them for component i.
- Then any number of IssuerAllowlist accounts covering the components' powers.
Arguments
| Argument | Type |
|---|---|
args | CreatePodArgs |
Checks and invariants
- 2 to 10 components, no duplicates, and none of them the pod mint itself.
- wrap_fee_bps and unwrap_fee_bps ≤ 200; creator_share_bps ≤ 1,000; burn share = 10,000 − protocol share − creator share.
- Every recipe unit is non-zero and genesis_amount ≥ 1 whole cohort (10⁹ raw).
- Each component mint is owned by SPL Token or Token-2022, has no TransferFee and no extension outside the allowed set, and is not paused.
- Every freeze authority, permanent delegate, pause authority, hook authority and hook program on a component is on the allowlist. The mint authority is not checked.
- Each vault is the canonical associated token account, owned by the pod, not frozen, with no delegate and no close authority.
- The pod mint has MetadataPointer and TokenMetadata only, 9 decimals, mint authority = the Pod PDA and no freeze authority.
- Genesis deposit per component = ceil(genesis_amount × recipe_units ÷ 10⁹). The creator receives genesis_amount cohorts with no fee.
- The protocol share in the config at this moment is copied into the pod and never changes for it. The pod starts unverified.
- Blocked while wraps_paused is set.
Program errors
6002 WrapsPaused6003 InvalidComponentCount6004 FeeTooHigh6005 CreatorShareTooHigh6006 InvalidFeeSplit6009 MetadataTooLong6011 ZeroRecipeUnits6012 GenesisTooSmall6014 LengthMismatch6015 MissingAccounts6042 InvalidAllowlistAccount6018 InvalidTokenProgram6017 DuplicateComponent6019 InvalidMint6021 TransferFeeNotAllowed6022 DisallowedExtension6023 IssuerNotAllowlisted6026 ComponentPaused6024 InvalidVault6025 VaultFrozen6020 InvalidTokenAccount6013 ZeroAmount6030 UnexpectedTransferAmount6000 MathOverflow
wrapSDK: wrap
Deposits every component pro-rata and mints pod_amount cohorts gross: the fee to the FeeVault, the rest to the user.
Signer · Anyone holding the components.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | user | mutsigner | |
| 1 | config | ||
| 2 | pod | mut | |
| 3 | pod_mint | mut | |
| 4 | fee_vault | mut | |
| 5 | user_pod_account | mut | |
| 6 | pod_token_program |
Remaining accounts
- Per component, 4 accounts: mint, vault, user's source token account, token program.
- Then transfer-hook extras, hook_extras[i] for component i (an empty hook_extras means none).
Arguments
| Argument | Type |
|---|---|
pod_amount | u64 |
max_in | Vec<u64> |
hook_extras | bytes |
Checks and invariants
- Before pricing, each component is synced: if the vault holds less than tracked_balance + claims_outstanding, the gap is recorded as shortfall.
- amount_in[i] = ceil(pod_amount × tracked_balance[i] ÷ supply), or ceil(pod_amount × recipe_units[i] ÷ 10⁹) when supply is 0. It must be ≤ max_in[i].
- The vault must grow by exactly amount_in[i], or the wrap fails.
- fee = ceil(pod_amount × wrap_fee_bps ÷ 10,000). The user gets pod_amount − fee.
- Fails if a component's transfer-hook program differs from the one recorded at creation.
- Blocked while wraps_paused is set.
Program errors
6002 WrapsPaused6013 ZeroAmount6014 LengthMismatch6015 MissingAccounts6016 ComponentMismatch6018 InvalidTokenProgram6019 InvalidMint6027 HookChanged6020 InvalidTokenAccount6028 SlippageExceededIn6030 UnexpectedTransferAmount6031 ZeroBacking6000 MathOverflow
unwrapSDK: unwrap
Returns pod_amount cohorts: the fee goes to the FeeVault, the rest is burned, and every component is paid out pro-rata.
Signer · Any holder.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | user | mutsigner | |
| 1 | pod | mut | |
| 2 | pod_mint | mut | |
| 3 | fee_vault | mut | |
| 4 | user_pod_account | mut | |
| 5 | pod_token_program | ||
| 6 | system_program |
Remaining accounts
- Per component, 4 accounts: mint, vault, user's destination token account, token program.
- Then transfer-hook extras, hook_extras[i] for component i.
Arguments
| Argument | Type |
|---|---|
pod_amount | u64 |
min_out | Vec<u64> |
hook_extras | bytes |
Checks and invariants
- Takes no config account, so no protocol switch can stop it.
- pod_amount ≤ supply. fee = ceil(pod_amount × unwrap_fee_bps ÷ 10,000); net = pod_amount − fee must be > 0.
- Each component is synced first, so a pending seizure is charged before anyone is paid.
- amount_out[i] = floor(net × tracked_balance[i] ÷ supply) and must be ≥ min_out[i].
- If any component is paused or frozen, its token transfer fails and so does the whole unwrap. Use unwrap_partial.
Program errors
6013 ZeroAmount6014 LengthMismatch6032 AmountExceedsSupply6033 UnwrapTooSmall6015 MissingAccounts6016 ComponentMismatch6018 InvalidTokenProgram6020 InvalidTokenAccount6029 SlippageExceededOut6000 MathOverflow
unwrap_partialSDK: unwrapPartial
Same as unwrap, but the components named in skip_mask are written to ClaimTicket accounts instead of being transferred.
Signer · Any holder, who pays rent for the tickets and gets it back on redemption.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | user | mutsigner | |
| 1 | pod | mut | |
| 2 | pod_mint | mut | |
| 3 | fee_vault | mut | |
| 4 | user_pod_account | mut | |
| 5 | pod_token_program | ||
| 6 | system_program |
Remaining accounts
- Per component, 4 accounts: mint, vault, user's destination token account, token program.
- Then transfer-hook extras, hook_extras[i] for component i.
- Then one ClaimTicket PDA per skipped component, in component order: seeds ["claim", pod, owner, component_index, nonce as u64 little-endian].
Arguments
| Argument | Type |
|---|---|
pod_amount | u64 |
min_out | Vec<u64> |
skip_mask | u16 |
nonce | u64 |
hook_extras | bytes |
Checks and invariants
- skip_mask ≠ 0 and has no bit at or above the component count.
- A component may be skipped only if it is blocked right now: its mint is paused, its vault is frozen, the user's destination account for it is frozen, or its transfer-hook program differs from the one recorded at creation.
- The ticket amount is computed exactly like an unwrap payout, rounded down, and is checked against min_out[i] too.
- The ticketed amount leaves tracked_balance and is added to claims_outstanding, so it stays in the vault reserved for the ticket holder.
- A (pod, owner, index, nonce) ticket can exist once; reusing a nonce while the ticket is open fails.
Program errors
6013 ZeroAmount6014 LengthMismatch6034 InvalidSkipMask6032 AmountExceedsSupply6033 UnwrapTooSmall6015 MissingAccounts6016 ComponentMismatch6018 InvalidTokenProgram6019 InvalidMint6020 InvalidTokenAccount6029 SlippageExceededOut6035 ComponentNotBlocked6036 InvalidClaimTicket6000 MathOverflow
redeem_claimSDK: redeemClaim
Pays out a claim ticket and closes it, returning the ticket's rent to its owner.
Signer · The ticket's owner.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | owner | mutsigner | |
| 1 | pod | mut | |
| 2 | ticket | mut | |
| 3 | mint | ||
| 4 | vault | mut | |
| 5 | owner_token_account | mut | |
| 6 | token_program |
Remaining accounts
- Transfer-hook extras for the component's transfer, if it has a hook.
Arguments
None.
Checks and invariants
- No admin switch is consulted. The program doesn't check for a pause itself: the token transfer simply fails while the component still can't move, and the ticket stays open.
- Pays exactly raw_amount and lowers claims_outstanding by the same amount.
Program errors
6001 Unauthorized6036 InvalidClaimTicket6016 ComponentMismatch6039 InvalidComponentIndex6000 MathOverflow
distribute_feesSDK: distributeFees
Empties the pod's FeeVault: pays the creator and protocol shares and burns everything else.
Signer · Anyone. It is a permissionless crank that pays the caller nothing.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | payer | signer | Anyone may crank. |
| 1 | config | ||
| 2 | pod | ||
| 3 | pod_mint | mut | |
| 4 | fee_vault | mut | |
| 5 | creator_pod_account | mut | |
| 6 | treasury_pod_account | mut | |
| 7 | pod_token_program |
Arguments
None.
Checks and invariants
- to_creator = floor(fees × creator_share_bps ÷ 10,000); to_protocol = floor(fees × protocol_share_bps ÷ 10,000); burned = fees − to_creator − to_protocol.
- Rounding dust therefore burns rather than being paid out.
- The recipients must be Token-2022 pod-token accounts owned by pod.creator and config.treasury.
- Burning lowers supply without touching any vault, so backing per cohort rises.
Program errors
6037 NoFees6038 InvalidFeeRecipient6020 InvalidTokenAccount6000 MathOverflow
reconcileSDK: reconcile
Compares one component vault with the program's books and records any deficit as shortfall.
Signer · Anyone.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | pod | mut | |
| 1 | vault |
Arguments
| Argument | Type |
|---|---|
component_index | u8 |
Checks and invariants
- Expected = tracked_balance + claims_outstanding. A vault below that is a seizure; the deficit (capped at tracked_balance) moves from tracked_balance to shortfall.
- A vault above that (a donation) is ignored and never enters share math.
- Idempotent: running it twice records nothing new. wrap and unwrap run the same sync on every component anyway.
Program errors
6039 InvalidComponentIndex6016 ComponentMismatch6020 InvalidTokenAccount6000 MathOverflow
set_creator_shareSDK: setCreatorShare
Lowers the creator's share of fees.
Signer · pod.creator.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | creator | signer | |
| 1 | pod | mut |
Arguments
| Argument | Type |
|---|---|
new_bps | u16 |
Checks and invariants
- new_bps must be strictly lower than the current creator share.
- The freed share is added to burn_share_bps, never redirected, so burn + creator + protocol stays 10,000.
Program errors
6001 Unauthorized6008 CreatorShareCanOnlyDecrease6000 MathOverflow
set_lookup_tableSDK: setLookupTable
Records an address lookup table for the pod, once, so large pods fit a wrap or unwrap in one transaction.
Signer · Anyone.
Accounts
| # | Account | Notes | |
|---|---|---|---|
| 0 | pod | mut | |
| 1 | lookup_table |
Arguments
None.
Checks and invariants
- The table must be frozen (no authority, never deactivated), so it can't be closed or changed later.
- It must contain the pod, the pod mint, the fee vault and every component's mint and vault.
- Only possible while pod.lookup_table is unset.
Program errors
Accounts and PDAs
Four account types. The pod-token FeeVault and every component vault are ordinary associated token accounts owned by the Pod PDA (the FeeVault under Token-2022), not program accounts. Derive the PDAs with the SDK’s configPda, issuerPda, podPda and claimPda.
PublicKey.findProgramAddressSync([Buffer.from("config")], programId);
PublicKey.findProgramAddressSync([Buffer.from("issuer"), key.toBuffer()], programId);
PublicKey.findProgramAddressSync([Buffer.from("pod"), podMint.toBuffer()], programId);
PublicKey.findProgramAddressSync(
[Buffer.from("claim"), pod.toBuffer(), owner.toBuffer(), Buffer.from([componentIndex]), nonceLe8],
programId,
);ProtocolConfig
Global protocol configuration. Seeds: `["config"]`.
- PDA seeds
["config"]- Space
85bytes allocated, including the 8-byte discriminator
| Offset | Field | Type | Size | Notes |
|---|---|---|---|---|
| 0 | discriminator | [u8; 8] | 8 | sha256("account:ProtocolConfig")[..8] |
| 8 | admin | Pubkey | 32 | |
| 40 | treasury | Pubkey | 32 | |
| 72 | protocol_share_bps | u16 | 2 | Protocol share of fees (bps) applied to pods created from now on. |
| 74 | max_components | u8 | 1 | |
| 75 | wraps_paused | bool | 1 | Blocks new wraps and pod creation only. Unwrapping can never be paused. |
| 76 | pod_count | u64 | 8 | |
| 84 | bump | u8 | 1 |
IssuerAllowlist
Existence of this account marks `key` (an issuer authority, permanent delegate or transfer-hook program) as accepted. Seeds: `["issuer", key]`.
- PDA seeds
["issuer", key]- Space
77bytes allocated, including the 8-byte discriminator
| Offset | Field | Type | Size | Notes |
|---|---|---|---|---|
| 0 | discriminator | [u8; 8] | 8 | sha256("account:IssuerAllowlist")[..8] |
| 8 | key | Pubkey | 32 | |
| 40 | label | string | 36 | |
| — | bump | u8 | 1 |
Pod
A pod. Seeds: `["pod", pod_mint]`.
- PDA seeds
["pod", pod_mint]- Space
1762bytes allocated, including the 8-byte discriminator
| Offset | Field | Type | Size | Notes |
|---|---|---|---|---|
| 0 | discriminator | [u8; 8] | 8 | sha256("account:Pod")[..8] |
| 8 | creator | Pubkey | 32 | |
| 40 | pod_mint | Pubkey | 32 | |
| 72 | fee_vault | Pubkey | 32 | |
| 104 | lookup_table | Pubkey | 32 | Frozen address lookup table for large pods (default = unset). |
| 136 | wrap_fee_bps | u16 | 2 | |
| 138 | unwrap_fee_bps | u16 | 2 | |
| 140 | burn_share_bps | u16 | 2 | |
| 142 | creator_share_bps | u16 | 2 | |
| 144 | protocol_share_bps | u16 | 2 | |
| 146 | verified | bool | 1 | |
| 147 | bump | u8 | 1 | |
| 148 | components | Vec<Component> | 1614 |
ClaimTicket
Raw units of a paused/frozen component owed to `owner`. Seeds: `["claim", pod, owner, component_index, nonce_le]`.
- PDA seeds
["claim", pod, owner, component_index, nonce_le]- Space
122bytes allocated, including the 8-byte discriminator
| Offset | Field | Type | Size | Notes |
|---|---|---|---|---|
| 0 | discriminator | [u8; 8] | 8 | sha256("account:ClaimTicket")[..8] |
| 8 | pod | Pubkey | 32 | |
| 40 | owner | Pubkey | 32 | |
| 72 | mint | Pubkey | 32 | |
| 104 | component_index | u8 | 1 | |
| 105 | nonce | u64 | 8 | |
| 113 | raw_amount | u64 | 8 | |
| 121 | bump | u8 | 1 |
Types
CreatePodArgs
| Field | Type | Size | Notes |
|---|---|---|---|
name | string | var | |
symbol | string | var | |
uri | string | var | |
recipe_units | Vec<u64> | var | Raw units of each component per 1 whole cohort token. |
wrap_fee_bps | u16 | 2 | |
unwrap_fee_bps | u16 | 2 | |
creator_share_bps | u16 | 2 | |
genesis_amount | u64 | 8 | Pod tokens (raw, 9 decimals) minted to the creator by the genesis wrap. |
hook_extras | bytes | var | Transfer-hook extra account count per component (empty = none). |
Component161 bytes
| Field | Type | Size | Notes |
|---|---|---|---|
mint | Pubkey | 32 | |
token_program | Pubkey | 32 | |
vault | Pubkey | 32 | ATA(pod, mint, token_program). |
hook_program | Pubkey | 32 | Transfer-hook program at creation (default = none). Wraps are blocked if it changes. |
decimals | u8 | 1 | |
recipe_units | u64 | 8 | Raw units of this component per 1 whole cohort token at genesis. |
tracked_balance | u64 | 8 | Program-tracked balance backing outstanding cohort tokens. All share math uses this. |
shortfall | u64 | 8 | Cumulative amount detected as removed by the issuer (socialised in this pod). |
claims_outstanding | u64 | 8 | Raw units held in the vault for unredeemed claim tickets. |
Events
Emitted through Anchor’s emit! into the transaction logs.
| Event | Fields |
|---|---|
PodCreated | pod: Pubkey, pod_mint: Pubkey, creator: Pubkey, genesis_amount: u64 |
Wrapped | pod: Pubkey, user: Pubkey, pod_amount: u64, fee: u64, amounts_in: Vec<u64> |
Unwrapped | pod: Pubkey, user: Pubkey, pod_amount: u64, fee: u64, amounts_out: Vec<u64>, skip_mask: u16 |
ClaimCreated | pod: Pubkey, ticket: Pubkey, owner: Pubkey, component_index: u8, raw_amount: u64 |
ClaimRedeemed | pod: Pubkey, ticket: Pubkey, owner: Pubkey, raw_amount: u64 |
FeesDistributed | pod: Pubkey, burned: u64, to_creator: u64, to_protocol: u64 |
ShortfallDetected | pod: Pubkey, component_index: u8, amount: u64, tracked_balance: u64 |
Error codes
Custom program errors start at 6000 (0x1770). A failed transaction reports them as custom program error: 0x…. Match the hex against this table; @cohort/sdk exports the same list as IDL.errors.
| Code | Hex | Name | Message | Raised by |
|---|---|---|---|---|
| 6000 | 0x1770 | MathOverflow | Arithmetic overflow | create_pod wrap unwrap unwrap_partial redeem_claim distribute_fees reconcile set_creator_share |
| 6001 | 0x1771 | Unauthorized | Signer is not authorized for this action | initialize_config set_wraps_paused add_issuer remove_issuer set_pod_verified redeem_claim set_creator_share |
| 6002 | 0x1772 | WrapsPaused | New wraps are paused by the protocol | create_pod wrap |
| 6003 | 0x1773 | InvalidComponentCount | A pod needs between 2 and 10 components | create_pod |
| 6004 | 0x1774 | FeeTooHigh | Wrap/unwrap fee exceeds 200 bps | create_pod |
| 6005 | 0x1775 | CreatorShareTooHigh | Creator share exceeds 1000 bps | create_pod |
| 6006 | 0x1776 | InvalidFeeSplit | burn + creator + protocol shares must equal 10000 bps | create_pod |
| 6007 | 0x1777 | ProtocolShareTooHigh | Protocol share exceeds the allowed maximum | initialize_config |
| 6008 | 0x1778 | CreatorShareCanOnlyDecrease | Creator share can only be lowered | set_creator_share |
| 6009 | 0x1779 | MetadataTooLong | Name, symbol or URI too long | create_pod |
| 6010 | 0x177a | LabelTooLong | Label too long | add_issuer |
| 6011 | 0x177b | ZeroRecipeUnits | Recipe units must be non-zero | create_pod |
| 6012 | 0x177c | GenesisTooSmall | Genesis wrap must be at least one whole cohort token | create_pod |
| 6013 | 0x177d | ZeroAmount | Amount must be greater than zero | create_pod wrap unwrap unwrap_partial |
| 6014 | 0x177e | LengthMismatch | Argument vector length does not match the number of components | create_pod wrap unwrap unwrap_partial |
| 6015 | 0x177f | MissingAccounts | Not enough remaining accounts for the components | create_pod wrap unwrap unwrap_partial |
| 6016 | 0x1780 | ComponentMismatch | Component account does not match the pod | wrap unwrap unwrap_partial redeem_claim reconcile |
| 6017 | 0x1781 | DuplicateComponent | Duplicate component mint | create_pod |
| 6018 | 0x1782 | InvalidTokenProgram | Account is not owned by an SPL token program | create_pod wrap unwrap unwrap_partial |
| 6019 | 0x1783 | InvalidMint | Account is not a valid mint | create_pod wrap unwrap_partial |
| 6020 | 0x1784 | InvalidTokenAccount | Account is not a valid token account | create_pod wrap unwrap unwrap_partial distribute_fees reconcile |
| 6021 | 0x1785 | TransferFeeNotAllowed | Mints with a TransferFee extension are not allowed | create_pod |
| 6022 | 0x1786 | DisallowedExtension | Mint has an extension that is not allowed | create_pod |
| 6023 | 0x1787 | IssuerNotAllowlisted | Mint authority/delegate/hook is not on the issuer allowlist | create_pod |
| 6024 | 0x1788 | InvalidVault | Vault is not the canonical associated token account of the pod | create_pod |
| 6025 | 0x1789 | VaultFrozen | Vault is frozen | create_pod |
| 6026 | 0x178a | ComponentPaused | Component mint is paused | create_pod |
| 6027 | 0x178b | HookChanged | Transfer hook program changed since pod creation; new wraps are blocked | wrap |
| 6028 | 0x178c | SlippageExceededIn | Amount in exceeds max_in (slippage) | wrap |
| 6029 | 0x178d | SlippageExceededOut | Amount out below min_out (slippage) | unwrap unwrap_partial |
| 6030 | 0x178e | UnexpectedTransferAmount | Vault received an unexpected amount | create_pod wrap |
| 6031 | 0x178f | ZeroBacking | Pod has no backing to wrap against | wrap |
| 6032 | 0x1790 | AmountExceedsSupply | Amount exceeds pod supply | unwrap unwrap_partial |
| 6033 | 0x1791 | UnwrapTooSmall | Unwrap amount is too small to pay out after fees | unwrap unwrap_partial |
| 6034 | 0x1792 | InvalidSkipMask | Invalid skip mask | unwrap_partial |
| 6035 | 0x1793 | ComponentNotBlocked | Component can move; it cannot be turned into a claim ticket | unwrap_partial |
| 6036 | 0x1794 | InvalidClaimTicket | Claim ticket account does not match the expected PDA | unwrap_partial redeem_claim |
| 6037 | 0x1795 | NoFees | Nothing to distribute | distribute_fees |
| 6038 | 0x1796 | InvalidFeeRecipient | Fee recipient account is invalid | distribute_fees |
| 6039 | 0x1797 | InvalidComponentIndex | Component index out of range | redeem_claim reconcile |
| 6040 | 0x1798 | LookupTableAlreadySet | Lookup table already set for this pod | set_lookup_table |
| 6041 | 0x1799 | InvalidLookupTable | Lookup table is invalid, mutable, or missing pod addresses | set_lookup_table |
| 6042 | 0x179a | InvalidAllowlistAccount | Invalid issuer allowlist account | create_pod |