Skip to content

Core Concepts

Domain model: Pool → ShareClass → Vault

Vaults follow the Centrifuge model: Pool → ShareClass → Vault. A vault is identified by its on-chain address; it has a poolId and a vaultKind. A share class can have multiple vault deployments (possibly on multiple chains) — VaultFinancials.vaults lists the sibling deployments.

Two identifier types appear throughout the API:

  • Vault address (0x…, on-chain contract address) — keys everything on-chain and the address-only API endpoints (getVaultFinancials, getSharePriceHistory, getVaultTransactions).
  • Share-class id (hex string, e.g. "0x0001…") — keys the share-class-scoped API endpoints (return history, TVL history, asset distribution, fees). You never need to know it in advance: useVaultFinancials(vaultAddress) / getVaultFinancials() returns it as shareClassId.

Vault types

type VaultType = 'ASYNC' | 'SYNC_DEPOSIT_ASYNC_REDEEM';

Mapped from the on-chain vaultKind: 0 → 'ASYNC', any other value → 'SYNC_DEPOSIT_ASYNC_REDEEM'.

  • 'ASYNC' — both deposit and redeem are asynchronous (ERC-7540 request → epoch → claim).
  • 'SYNC_DEPOSIT_ASYNC_REDEEM' — deposit is synchronous (plain ERC-4626 deposit(), shares mint immediately); redeem is still asynchronous.

The ERC-7540 request → epoch → claim lifecycle

DEPOSIT (ASYNC):             requestDeposit(assets) → [epoch] → deposit(assets) mints shares
DEPOSIT (SYNC_DEPOSIT...):   deposit(assets) mints shares immediately (ERC-4626)
REDEEM (both types):         requestRedeem(shares) → [epoch] → redeem(shares) returns assets
CANCEL DEPOSIT (ASYNC only): cancelDepositRequest() → [epoch] → claimCancelDepositRequest() returns assets
CANCEL REDEEM (both types):  cancelRedeemRequest() → [epoch] → claimCancelRedeemRequest() returns shares

Key rules:

  • requestId is always 0 — one request per user (controller) per vault.
  • Epoch execution is performed off-chain by the Arkonix operator. The SDK cannot trigger it; UIs must wait for the pending → claimable transition.
  • Detecting transitions: poll useVaultUserState — it auto-refetches every 10 s and exposes hasPending* / hasClaimable* booleans for every flow.
  • The "claim" of an async deposit is the ERC-4626 deposit(assets, receiver) call (this is intentional and standard-conformant — after the epoch, deposit fulfills the request).
  • Cancel-deposit is ASYNC vaults only (sync deposits settle immediately; there is nothing to cancel). The SDK fails early with a clear error rather than reverting on-chain.

See Deposit & Redeem Flows for working examples of each stage.

Decimals — the most common integration mistake

Asset and share tokens have different decimals (e.g. USDC = 6, shares = 18).

  • Asset amounts are parsed/formatted with assetDecimals.
  • Share amounts are parsed/formatted with shareDecimals.
  • Both come from useVaultMetadata / VaultReader.getMetadata — always read them from there rather than hard-coding.

USDC is 18 decimals on BSC

Do not assume USDC is 6 decimals everywhere: native USDC on BNB Smart Chain (chainId 56) has 18 decimals. Hard-coding 6 will mis-parse amounts by 12 orders of magnitude. Always take assetDecimals from vault metadata.

The three data sources

Source What it provides Config needed
On-chain (viem PublicClient) Metadata, balances, pending/claimable request state, conversions, transactions chainId + rpcUrl
Arkonix backend API (public, no auth) NAV/TVL, share price, returns, history series, user activity, asset distribution, fees arkonixAPI.baseUrl
Centrifuge GraphQL API Vault discovery across the ecosystem; legacy holdings (deprecated) optional centrifugeAPI (has default URL)

NAV, returns, and share price are not on the vault contract — they come from the Arkonix backend, keyed by vault address or share-class id. See Configuration for how each source is enabled.