Skip to main content
This walkthrough explains how to integrate Centrifuge vaults on Base and X Layer with a Para-powered EVM wallet. It is a step-by-step guide for depositing into and redeeming from Centrifuge vaults in a TypeScript web application. The vault sits in front of the Centrifuge protocol so integrators don’t have to deal with its complexity: you deposit USDC into the vault and receive the deRWA share token, which is transferable between non-frozen accounts.

Overview

The vaults in this guide provide a small contract interface for investing in tokenized real-world asset products. Users deposit an accepted asset, such as USDC, and receive product shares. Depending on the vault configuration, a deposit either completes immediately or enters a settlement queue. Redemptions are always asynchronous. The user submits a redemption request, waits for settlement, and then claims the resulting asset. The integration must therefore distinguish between:
  • Synchronous deposit: one transaction deposits the asset and returns deRWA tokens.
  • Asynchronous deposit: one transaction creates the request and a later transaction claims deRWA tokens.
  • Asynchronous redemption: one transaction creates the request and a later transaction claims the asset.

Reference Deployments

The examples use five live PassthroughVault deployments across two independent chains. Each chain has its own RPC endpoint, gas token, and USDC contract.

Base (Chain ID 8453, Gas in ETH)

X Layer (Chain ID 196, Gas in OKB)

The share token at 0x9c5C... was renamed onchain from deSPXA to JSPX on August 17, 2026. The address and 18-decimal precision did not change.
For protocol-level contracts and newly supported networks, see the Centrifuge deployments reference. Confirm product-specific passthrough vault addresses with Centrifuge before adding another deployment.

How It Works

Across the listed deployments, deposits are synchronous for deJAAA, deHYB, and deJTRSY, and asynchronous for JSPX. Redemptions are asynchronous (ERC-7540 style): you submit a request, the issuer fulfills it during their settlement cycle (this can take hours or days), and then you claim the result. Deposit mode is configured per passthrough vault, not per chain or product. Read asyncDeposit() from the vault instead of assuming a mode from its name. Three things to know before writing any code:
  1. There is no claim() function. Claiming a fulfilled deposit is done by calling deposit(...), and claiming a fulfilled redemption by calling redeem(...).
  2. Requests are self-directed. The controller and owner parameters in the request functions must be your own address.
  3. mint() and withdraw() don’t exist. Only deposit() and redeem() are supported, so don’t point generic ERC-4626/7540 tooling at this vault.
These deployments allow anyone to claim a controller’s entire settled balance on their behalf, but the receiver must be that same controller. Partial third-party claims are not supported.

What You Need

  • Node.js 18 or later for project tooling.
  • A package manager such as npm, pnpm, or yarn.
  • A Para API key, a completed Para authentication flow, and an EVM wallet for the authenticated user.
  • The Para Web SDK, Para’s viem integration, and viem.
  • A browser-exposed mainnet RPC URL for Base or X Layer.
  • The selected chain’s gas token: ETH on Base or OKB on X Layer.
  • USDC on the selected chain for deposits.
  • The authoritative vault ABI and a standard ERC-20 ABI.
  • A user interface that represents pending and claimable states separately.
  • Para handles signing without exposing or storing the user’s private key in your application.

Install Dependencies


Step-by-Step Integration (TypeScript + Para + viem)

All the code in this guide lives in a single file and uses Para’s Web SDK, Para’s viem integration, and viem.

Setup

Start with the Para and viem imports:
Define the supported deployments in one place. This walkthrough selects Base by default; change selectedNetwork to deployments.xLayer to use an X Layer sync-deposit or redemption flow.
We only need approve and balanceOf from the ERC-20s:
And from the vault, the request/claim functions plus the two views that track a request’s lifecycle in each direction:
Complete Para authentication before creating the account and clients. createParaViemAccount selects the first available EVM wallet unless you pass a specific address or walletId.
Finally, a small helper so every write waits for inclusion and fails loudly on revert:
That’s all the setup. Everything below uses these constants, clients, and the helper directly.

Case 1: Sync Deposit

In sync mode there is no request and no claim: approve USDC, call deposit, and the shares arrive in the same transaction.

Case 2: Async Deposit

JSPX on Base is the only asynchronous-deposit product in this guide. This case requires selectedNetwork = deployments.base and uses asyncProduct from that deployment.

Step 1: Approve USDC

The vault pulls your USDC when you submit the request, so it needs an allowance first. USDC uses 6 decimals:

Step 2: Submit the Request

requestDeposit takes the amount plus a controller and an owner. Both must be your own address (the caller). Your USDC is transferred immediately and the request enters the queue:

Step 3: Wait for Fulfillment

The issuer settles requests in epochs, so fulfillment is not instant. Two views, both denominated in USDC, tell you where your request stands: pending is what’s still queued and claimable is what’s already settled and ready.
Fulfillment can also be partial: requests settle in order across all investors, so claimable may cover only part of your request for a while. You can claim partial amounts as they become available.
In a real service, poll these views from a background job or cron. Fulfillment can take hours or days depending on the product’s settlement cycle.
Do not use pending === 0 as the only terminal signal. Rounding dust can leave a small pending amount that is not claimable, and these passthrough vaults do not expose request cancellation.

Step 4: Claim Your Shares

Once claimable > 0, claim by calling deposit. Passing maxUint256 as the amount claims everything that’s ready, so you don’t have to compute it first:
The JSPX shares (18 decimals) are now in your wallet:
One nice property: if you submit a new requestDeposit while you still have a claimable balance from a previous one, the vault auto-claims the old one to you first. You’ll never strand settled funds by re-requesting.

Case 3: Async Redemption

The redemption flow mirrors the asynchronous deposit flow: request, wait, and claim, but moving shares in and USDC out. The selected redemptionProduct can be any of the five products listed above as long as it belongs to selectedNetwork.

Step 1: Approve Shares

requestRedeem pulls the selected product’s shares via transferFrom, so approve the vault first. All share tokens listed in this guide use 18 decimals:

Step 2: Submit the Request

Same rule as deposits: controller and owner must be your own address.

Step 3: Wait for Fulfillment

Same pattern as deposits, with the redeem-side views. Note these are denominated in shares, not USDC:

Step 4: Claim Your USDC

Claim by calling redeem. Again, maxUint256 claims everything that’s settled:
The example selects deJAAA. On Base, set redemptionProduct to selectedNetwork.products.jspx to redeem JSPX. On X Layer, select deJAAA, deHYB, or deJTRSY from selectedNetwork.products.

Conclusions

These passthrough vaults use the same transaction interface across Base and X Layer. Synchronous deposits complete atomically, while JSPX deposits and every listed product’s redemptions use a request-and-claim lifecycle. Selecting another listed deployment changes the chain, RPC URL, USDC address, vault address, and share-token address without changing Para’s authentication or signing flow.