> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stablecoin Yield via Upshift Vaults

> Deposit into and redeem from Upshift stablecoin vaults, from 24/7 tokenized money market funds to DeFi, with Para embedded wallets.

> [!NOTE]
>
> **Looking for the full documentation?** Visit the [Upshift SDK docs](https://docs.upshift.finance/sdk/quick-start) for the complete SDK reference.

Upshift vaults let a Para-powered wallet earn yield on stablecoins. This guide covers the full lifecycle with the Upshift SDK (`@upshiftfinance/sdk`): discovering vaults, depositing, tracking positions, and redeeming. Users keep their vault shares in their own Para wallet.

## What You'll Learn

* How to create a Para-backed viem wallet client and pass it to the Upshift SDK
* How to deposit a stablecoin into an Upshift vault
* How to show a user's position and request a redemption

> [!NOTE]
>
> **Version scope:** The examples target `@upshiftfinance/sdk@0.5.0` with `@getpara/web-sdk` and `@getpara/viem-v2-integration` `3.25.0`.

## Why Combine Para and Upshift

| Para Wallets | Upshift Vaults |
| - | - |
| Embedded wallets with email, social, or passkey sign-in and no seed phrase | Stablecoin vaults across a range of risk levels through one integration |
| Non-custodial MPC wallets: your app never holds user funds | A professional curator runs each strategy within limits set for that vault |
| Para-backed EVM accounts that work with viem | One SDK covers deposits, positions, and redemptions |

## Example Use Cases

1. **Savings in a wallet or fintech app:** Give users a default "savings" balance backed by a tokenized money market fund.
2. **Consumer yield product:** Offer an opt-in, higher-yield option next to a cash balance.
3. **Business treasury:** Let a company wallet put idle operating balances to work.
4. **Backend reporting:** Read Upshift vault data and positions from your server to power dashboards and notifications.

## What You Need

* A Para API key and a [Para authentication flow](https://docs.getpara.com/v3/react/guides/custom-ui-web-sdk.md) that gives the user an EVM wallet
* An EVM RPC URL for each chain you use, for example from Alchemy or Infura
* The Upshift SDK, `@upshiftfinance/sdk`
* For browser apps: your domain on the Upshift API allowlist (see the warning in Step 1)

You do not need an Upshift API key for the calls in this guide.

## How Upshift Vaults Work

Each vault is a smart contract with one or more deposit assets (for example USDC or USDT), a strategy run by a professional curator, and a receipt token that represents the depositor's share. Upshift's contracts are audited, and the reports are public: [Audits & Risk](https://docs.upshift.finance/resources/audits).

Upshift runs vaults across a range of risk levels:

| Band | Example underlying | Typical use |
| - | - | - |
| Cash | 24/7 tokenized money market funds (T-bills) | Default "savings" balance |
| Core | Curated onchain and offchain prime lending | Higher yield for operating balances |
| Enhanced | Market-neutral and DeFi strategies | Opt-in, higher yield |

Returns are variable and come from the underlying strategy.

### Deposit lifecycle

```
Step 1 - approve the deposit asset (ERC-20)
Step 2 - call vaultDeposit()
         +--> shares are minted to the user's Para wallet in the same transaction
```

### Redemption lifecycle

```
Step 1 - call vaultRequestRedeem(shares)
         +--> shares are escrowed by the vault
Step 2 - Upshift processes claimable redemptions daily
         +--> assets are released to the user according to the vault's withdrawal terms
Optional - instant redemption (isInstantRedeem: true) on vaults that support it
```

Every deposit, approval, and redemption request is a regular EVM transaction that the user's Para wallet signs. The Upshift SDK signs through the viem wallet client you give it, so no browser extension is involved.

## Supported Networks

Upshift vaults run on more than a dozen EVM chains, including Ethereum, Base, BNB Chain, Avalanche, Monad, Flare, HyperEVM, and Plasma, plus Solana and Stellar. This guide covers EVM vaults. Every vault the SDK returns includes its `chainId`.

> [!NOTE]
>
> Create the Para wallet client with the vault's chain, and add that chain's RPC URL to the SDK `providers`. The examples below use Ethereum mainnet (`chainId: 1`).

## Step-by-Step Integration

### Step 1: Install Dependencies

```shell theme={null}
npm install @upshiftfinance/sdk @getpara/web-sdk @getpara/viem-v2-integration viem
```

`viem` is a peer dependency of `@upshiftfinance/sdk`.

> [!WARNING]
>
> **Browser apps:** The SDK calls the Upshift API (`api.augustdigital.io`) from the user's browser, and the API only accepts allowlisted origins. [Contact Upshift](https://www.upshift.finance) with your domain before you go live. Calls made from a server do not need this.

### Step 2: Initialize Para and the Upshift SDK

The code below creates the clients, but it does **not** implement Para login. Complete your app's [Para authentication flow](https://docs.getpara.com/v3/react/guides/custom-ui-web-sdk.md) first. `createParaViemAccount` uses the user's EVM wallet, so it throws if the user is not logged in or has no EVM wallet yet.

```typescript theme={null}
import { ParaWeb } from "@getpara/web-sdk";
import {
  createParaViemAccount,
  createParaViemClient,
} from "@getpara/viem-v2-integration";
import UpshiftSDK from "@upshiftfinance/sdk";
import { http } from "viem";
import { mainnet } from "viem/chains";

const RPC_URL = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY";

const para = new ParaWeb("YOUR_PARA_API_KEY");

// Run your Para login flow before this point.
if (!(await para.isFullyLoggedIn())) {
  throw new Error("Log the user in with Para first");
}

const account = createParaViemAccount({ para });
const walletClient = createParaViemClient({
  para,
  walletClientConfig: { account, chain: mainnet, transport: http(RPC_URL) },
});

const sdk = new UpshiftSDK({
  appName: "your-app-name",
  providers: { 1: RPC_URL },
});

sdk.evm.setSigner(walletClient);
const owner = account.address;
```

`appName` is required. Use a stable slug for your app: 3 to 64 characters, using only letters, digits, `.`, `_`, and `-`. Upshift uses it to identify your integration and to reach you about breaking changes.

> [!TIP]
>
> If your React app already uses `@getpara/react-sdk` and `ParaProvider`, reuse that authenticated Para instance instead of creating a second client. You can also get the wallet client from [`useParaViemClient`](https://docs.getpara.com/v3/react/guides/hooks/use-para-viem-client) and pass it to `sdk.evm.setSigner`.

### Step 3: Discover Vaults

Upshift gives you a short list of launch vaults for your integration. The launch vaults for Para are:

| Vault | Chain | Address | Deposit assets |
| - | - | - | - |
| Sentora USD | Ethereum (`1`) | `0x74aD2F789Ed583DBd141bbdafC673fE1F033718b` | USDC, USDT, PYUSD, RLUSD |
| NEMO ETH Prime | Ethereum (`1`) | `0xA422C3018C46ba90a14AcD14f96CB60616F5c91B` | WETH |

Fetch each one by address:

```typescript theme={null}
const VAULT = "0x74aD2F789Ed583DBd141bbdafC673fE1F033718b"; // Sentora USD
const vault = await sdk.getVault({ vault: VAULT, chainId: 1 });

console.log(vault.name, vault.depositAssets, vault.totalAssets.normalized);
```

Each vault includes its deposit assets, TVL, APY history, and strategy metadata. Useful fields for your UI:

| Field | Meaning |
| - | - |
| `depositAssets` | Tokens the vault accepts, each with `address`, `symbol`, and `decimals` |
| `isDepositPaused` | `true` when new deposits are paused |
| `lagDuration` | Redemption lag in seconds, for a "withdrawals take about N days" label |
| `instant_redeem_config` | Set only on vaults that support instant redemption |

> [!TIP]
>
> `sdk.getVaults({ chainIds: [1] })` returns every vault on the chain, including vaults that are not meant for your users. It also reads each vault onchain, so it can take tens of seconds. For a launch, use the addresses Upshift gives you and call `getVault`.

### Step 4: Deposit

1. Pick the deposit asset from `vault.depositAssets`.
2. Check the remaining deposit cap with `maxDeposit`, and preview the shares with `previewDeposit`.
3. Approve the deposit asset with `approve`. The SDK sets the correct spender for the vault.
4. Call `vaultDeposit`. Shares are minted to the user's Para wallet in the same transaction.

```typescript theme={null}
import { parseUnits, type Address } from "viem";

// Reuses `VAULT` and `vault` from Step 3
const asset = vault.depositAssets.find((a) => a.symbol === "USDC")!;
const assetAddress = asset.address as Address;
const amount = "100";

// 1. Cap and preview: both use raw units (100 USDC = 100_000_000n)
const cap = await sdk.evm.maxDeposit({ vault: VAULT, receiver: owner });
const shares = await sdk.evm.previewDeposit({
  vault: VAULT,
  amount: parseUnits(amount, asset.decimals),
  asset: assetAddress,
});

// 2. Approve if needed (human-readable amount)
const approval = await sdk.evm.approve({
  target: VAULT,
  wallet: owner,
  amount,
  depositAsset: assetAddress,
  wait: true,
});
if (approval.kind === "sent") console.log("approval tx", approval.hash);

// 3. Deposit (human-readable amount)
const txHash = await sdk.evm.vaultDeposit({
  target: VAULT,
  wallet: owner,
  amount,
  depositAsset: assetAddress,
  wait: true,
});
```

`approval.kind` is `"sent"` when an approval transaction was sent, and `"sufficient"` when the existing allowance already covers the amount. The user's Para wallet needs ETH for gas on each transaction.

> [!NOTE]
>
> Always pass `asset` to `previewDeposit`. Multi-asset vaults need it, and single-asset vaults ignore it.

### Step 5: Show Positions

```typescript theme={null}
const positions = await sdk.getVaultPositions({ wallet: owner, chainId: 1 });

for (const p of positions) {
  console.log(p.vault, p.walletBalance.normalized, p.redeemable.normalized);
}
```

`walletBalance` is the user's share balance. `redeemable` is the amount they can claim now. Each position also lists its `pendingRedemptions` and `availableRedemptions`.

### Step 6: Redeem

1. Call `vaultRequestRedeem` with the amount of **shares** to redeem. Set `isInstantRedeem: true` only if the user chooses instant redemption and the vault supports it.
2. Upshift processes claimable redemptions daily, so the user does not need to send a claim transaction. Timing depends on each vault's strategy, and `vault.lagDuration` gives the lag in seconds.
3. Call `getVaultAvailableRedemptions` to show pending and completed redemptions.

```typescript theme={null}
// Instant redemption is an opt-in alternative to the standard (queued) one,
// and only works on vaults that support it.
const supportsInstant =
  !!vault.instant_redeem_config && !vault.instant_redeem_config.isPaused;
const userChoseInstant = false; // from your UI

// amount is in shares
await sdk.evm.vaultRequestRedeem({
  target: VAULT,
  wallet: owner,
  amount: "50",
  isInstantRedeem: supportsInstant && userChoseInstant,
  wait: true,
});

// Track status
const { pendingRedemptions, availableRedemptions } =
  await sdk.getVaultAvailableRedemptions({
    vault: VAULT,
    chainId: 1,
    wallet: owner,
  });
```

> [!NOTE]
>
> Instant redemption is available only when `vault.instant_redeem_config` is set and its `isPaused` is `false`. A spread applies, shown in `instant_redeem_config.redeemableAssets[].spreadBps`.

> [!NOTE]
>
> If a vault cannot fund a redemption date yet, that redemption stays pending until the vault is funded.

### Step 7: Handle Errors

Every SDK method throws typed errors that extend `UpshiftSDKError`:

```typescript theme={null}
import {
  UpshiftSDKError,
  UpshiftTimeoutError,
  UpshiftValidationError,
} from "@upshiftfinance/sdk";

try {
  await sdk.evm.vaultDeposit({ target: VAULT, wallet: owner, amount: "100" });
} catch (err) {
  if (err instanceof UpshiftValidationError) {
    console.error("Check the input:", err.message);
  } else if (err instanceof UpshiftTimeoutError) {
    // The deposit may already be onchain. Check the user's position before retrying.
    console.error(`Timed out after ${err.timeoutMs} ms`);
  } else if (err instanceof UpshiftSDKError) {
    console.error(err.code, err.cause);
  } else {
    throw err;
  }
}
```

For example, a Para wallet without enough ETH for gas fails with an `UpshiftValidationError` whose `code` is `ACCOUNT_NOT_FUNDED`.

> [!WARNING]
>
> A timeout on a write call such as `vaultDeposit` doesn't mean the transaction failed. The Para wallet may already have signed and broadcast it. Before resending, check the user's position with `getVaultPositions` or look up the transaction, so the user doesn't deposit twice.

## Related Resources

> [card] [Upshift SDK Docs](https://docs.upshift.finance/sdk/quick-start)
>
> Full SDK reference and quick start

> [card] [Upshift Starter App](https://github.com/upshift-protocol/upshift-starter)
>
> Example app, live at starter.upshift.finance

> [card] [Para viem Setup](https://docs.getpara.com/v3/react/guides/web3-operations/evm/setup-libraries.md)
>
> Configure viem with Para wallets

> [card] [Audits and Risk](https://docs.upshift.finance/resources/audits)
>
> Upshift audit reports and risk disclosures

* **Vault catalog:** [app.upshift.finance](https://app.upshift.finance)
* **Branded vaults or fee share:** [Talk to Upshift](https://www.upshift.finance)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.