> ## 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.

# Aggregated Yield via Compass

> Add yield, lending, borrowing, and portfolio management to your app using Compass's non-custodial DeFi API and Para embedded wallets.

<Tip>
  For AI-friendly documentation, see [Para llms.txt](https://docs.getpara.com/llms.txt) and [Compass llms.txt](https://docs.compasslabs.ai/llms-full.txt).
</Tip>

If you're using Para for embedded wallets, you can now add yield, lending, borrowing, and portfolio management to your app using the Compass API. Your users get a full DeFi experience without ever managing approvals or interacting with protocols directly.

## How It Works

Compass provides a non-custodial DeFi API — you call an endpoint, get back an unsigned payload, and the user signs it via their Para wallet. Users earn yield, borrow against crypto, or rebalance portfolios without touching a DeFi protocol.

This walkthrough covers three products: **Earn** (deposit into Aave, Morpho, Pendle vaults), **Credit** (borrow stablecoins against collateral), and **Portfolio Manager** (atomic rebalancing across venues).

## Why Combine Para and Compass

| Para Wallets                                             | Compass API                                      |
| -------------------------------------------------------- | ------------------------------------------------ |
| Email/social login — no seed phrase or browser extension | Non-custodial DeFi across Aave, Morpho, Pendle   |
| EIP-712 signing — users see structured data, not hex     | Gas sponsorship — users never hold or pay ETH    |
| Embedded + external wallet support                       | Atomic transaction bundling — 50-70% gas savings |
| Multi-chain (Ethereum, Base, Arbitrum)                   | Embedded fees — monetize from day one            |

## Example Use Cases

1. **Yield Savings Account** — Users deposit USDC and earn 4-8% APY across vaults. You embed a 10% performance fee on yield. Users see one balance, one APY.

2. **Crypto-Backed Credit Line** — Users borrow USDC against ETH collateral. Display health factor and liquidation risk. Users never interact with Aave directly.

3. **Auto-Rebalancing Portfolio** — Monitor rates and rebalance atomically when better opportunities emerge. One signature moves \$50K from Aave (4.8%) to Morpho (6.2%).

<Tip>
  **Want to see what you'd be building?** Try [Compass Studio](https://studio.compasslabs.ai) — a visual interface for Earn, Credit, and Portfolio products. Explore vaults, simulate transactions, and copy working configurations into your app.
</Tip>

## What You Need

* A [Para SDK setup](https://docs.getpara.com/v3/react/setup/nextjs) with embedded wallets configured
* A **Compass API key** — get one free at [compasslabs.ai](https://compasslabs.ai)
* **Compass SDKs**: [TypeScript](https://www.npmjs.com/package/@compass-labs/api-sdk) · [Python](https://pypi.org/project/compass_api_sdk/) — both fully typed with all endpoints

### Gas Sponsorship (Recommended)

With gas sponsorship, your users never need ETH. You provide a **gas sponsor wallet** — a server-side private key funded with ETH on your target chain (Base, Ethereum, or Arbitrum). Your backend uses this wallet to pay gas and relay transactions on behalf of users. Compass returns EIP-712 typed data, the user signs it off-chain, and your sponsor wallet submits the transaction.

Without gas sponsorship, Compass returns a standard unsigned transaction that the user signs and broadcasts directly from their Para wallet. The user pays their own gas, which requires them to hold ETH.

This walkthrough uses gas sponsorship for all examples. See [Compass Gas Sponsorship docs](https://docs.compasslabs.ai/v2/Products/gas-sponsorship) for more details.

<Tip>
  You can also sponsor gas through [Account Abstraction integrations](/v3/react/guides/web3-operations/evm/account-abstraction) like Alchemy, Pimlico, or ZeroDev instead of running your own sponsor wallet.
</Tip>

## Step-by-Step Integration

### Step 1: Install the Compass SDK

Add the Compass TypeScript SDK alongside your existing Para setup. Para's `ParaProvider` already includes wagmi — the `useSignTypedData` hook used for EIP-712 signing is available out of the box.

```bash theme={null}
npm install @compass-labs/api-sdk
```

Add these server-side environment variables:

```bash theme={null}
# Server-side only — never expose to the client
COMPASS_API_KEY=your_compass_api_key
GAS_SPONSOR_PK=0x_your_sponsor_wallet_private_key
```

### Step 2: Create a Product Account

Compass uses isolated on-chain accounts ([Product Accounts](https://docs.compasslabs.ai/v2/Products/Accounts)) per product. Create a separate account for each product you plan to use — Earn, Credit, or both. Each account is a smart account controlled by the user's wallet. Compass never holds custody — it orchestrates creation and transaction routing.

Each account is deployed once per user. Calling the create endpoint again safely returns the existing address without a new transaction.

Your gas sponsor deploys these accounts so the user never needs ETH.

<Tabs>
  <Tab title="Create Earn Account">
    ```typescript theme={null}
    // app/api/earn-account/create/route.ts
    import { CompassApiSDK } from "@compass-labs/api-sdk";
    import { createWalletClient, createPublicClient, http } from "viem";
    import { privateKeyToAccount } from "viem/accounts";
    import { base, mainnet, arbitrum, type Chain } from "viem/chains";

    const viemChains: Record<string, Chain> = { base, ethereum: mainnet, arbitrum };

    export async function POST(request: Request) {
      const { owner, chain } = await request.json();

      const sdk = new CompassApiSDK({
        apiKeyAuth: process.env.COMPASS_API_KEY,
      });

      const sponsorAccount = privateKeyToAccount(
        process.env.GAS_SPONSOR_PK as `0x${string}`
      );

      const response = await sdk.earn.earnCreateAccount({
        chain,
        owner,                          // User's Para wallet address
        sender: sponsorAccount.address, // Your sponsor pays for deployment
        estimateGas: true,
      });

      // If account already exists, no transaction is returned
      if (!response.transaction) {
        return Response.json({ earnAccountAddress: response.earnAccountAddress });
      }

      const sponsorWallet = createWalletClient({
        account: sponsorAccount, chain: viemChains[chain], transport: http(),
      });

      const tx = response.transaction as any;
      const txHash = await sponsorWallet.sendTransaction({
        to: tx.to, data: tx.data,
        value: BigInt(tx.value || "0"),
        gas: tx.gas ? BigInt(tx.gas) : undefined,
      });

      await createPublicClient({ chain: viemChains[chain], transport: http() })
        .waitForTransactionReceipt({ hash: txHash });

      return Response.json({
        earnAccountAddress: response.earnAccountAddress,
        txHash,
      });
    }
    ```
  </Tab>

  <Tab title="Create Credit Account">
    ```typescript theme={null}
    // app/api/credit-account/create/route.ts
    import { CompassApiSDK } from "@compass-labs/api-sdk";
    import { createWalletClient, createPublicClient, http } from "viem";
    import { privateKeyToAccount } from "viem/accounts";
    import { base, mainnet, arbitrum, type Chain } from "viem/chains";

    const viemChains: Record<string, Chain> = { base, ethereum: mainnet, arbitrum };

    export async function POST(request: Request) {
      const { owner, chain } = await request.json();

      const sdk = new CompassApiSDK({
        apiKeyAuth: process.env.COMPASS_API_KEY,
      });

      const sponsorAccount = privateKeyToAccount(
        process.env.GAS_SPONSOR_PK as `0x${string}`
      );

      const response = await sdk.credit.creditCreateAccount({
        chain,
        owner,                          // User's Para wallet address
        sender: sponsorAccount.address, // Your sponsor pays for deployment
        estimateGas: true,
      });

      if (!response.transaction) {
        return Response.json({ creditAccountAddress: response.creditAccountAddress });
      }

      const sponsorWallet = createWalletClient({
        account: sponsorAccount, chain: viemChains[chain], transport: http(),
      });

      const tx = response.transaction as any;
      const txHash = await sponsorWallet.sendTransaction({
        to: tx.to, data: tx.data,
        value: BigInt(tx.value || "0"),
        gas: tx.gas ? BigInt(tx.gas) : undefined,
      });

      await createPublicClient({ chain: viemChains[chain], transport: http() })
        .waitForTransactionReceipt({ hash: txHash });

      return Response.json({
        creditAccountAddress: response.creditAccountAddress,
        txHash,
      });
    }
    ```
  </Tab>
</Tabs>

### Step 3: Fund Your Account

Before depositing into a vault or borrowing, move tokens from the user's wallet into their Product Account. This step teaches the **three-step signing pattern** that every gas-sponsored Compass operation follows.

Your backend requests EIP-712 typed data from Compass (**prepare**), the Para wallet signs it via wagmi's `useSignTypedData` (**sign**), and your backend submits the signed payload through your gas sponsor (**execute**).

<Tip>
  All amounts in the Compass API are in **human-readable units** (e.g., `"100"` means 100 USDC), not in base units or wei.
</Tip>

<Tabs>
  <Tab title="Backend — Prepare">
    ```typescript theme={null}
    // app/api/transfer/prepare/route.ts
    import { CompassApiSDK } from "@compass-labs/api-sdk";
    import { privateKeyToAccount } from "viem/accounts";

    export async function POST(request: Request) {
      const { owner, chain, token, amount } = await request.json();

      const sdk = new CompassApiSDK({
        apiKeyAuth: process.env.COMPASS_API_KEY,
      });

      const sponsorAccount = privateKeyToAccount(
        process.env.GAS_SPONSOR_PK as `0x${string}`
      );

      // Request EIP-712 typed data with gas sponsorship
      const transfer = await sdk.earn.earnTransfer({
        owner, chain,
        token,
        amount,
        action: "DEPOSIT",
        spender: sponsorAccount.address,
        gasSponsorship: true,
      });

      // For Credit accounts, use the same pattern:
      // const transfer = await sdk.credit.creditTransfer({
      //   owner, chain, token, amount,
      //   action: "DEPOSIT", spender: sponsorAccount.address,
      //   gasSponsorship: true,
      // });

      const eip712 = transfer.eip712!;

      // Gas-sponsored transfers use Permit2 — returns PermitTransferFrom types.
      // Product operations (earnManage, creditBorrow) return SafeTx types instead.
      // Normalize camelCase keys to PascalCase for wagmi.
      const normalizedTypes = {
        EIP712Domain: (eip712.types as any).eip712Domain,
        PermitTransferFrom: (eip712.types as any).permitTransferFrom,
        TokenPermissions: (eip712.types as any).tokenPermissions,
      };

      return Response.json({
        eip712, normalizedTypes,
        primaryType: eip712.primaryType,
        domain: eip712.domain,
        message: eip712.message,
      });
    }
    ```
  </Tab>

  <Tab title="Backend — Execute">
    ```typescript theme={null}
    // app/api/execute/route.ts — reused by ALL gas-sponsored operations
    import { CompassApiSDK } from "@compass-labs/api-sdk";
    import { createWalletClient, createPublicClient, http } from "viem";
    import { privateKeyToAccount } from "viem/accounts";
    import { base, mainnet, arbitrum, type Chain } from "viem/chains";

    const viemChains: Record<string, Chain> = { base, ethereum: mainnet, arbitrum };

    export async function POST(request: Request) {
      const { owner, eip712, signature, chain } = await request.json();

      const sdk = new CompassApiSDK({
        apiKeyAuth: process.env.COMPASS_API_KEY,
      });

      // Your gas sponsor wallet
      const sponsorAccount = privateKeyToAccount(
        process.env.GAS_SPONSOR_PK as `0x${string}`
      );

      // Compass wraps the user's EIP-712 signature into
      // a transaction that your sponsor can submit
      const sponsored = await sdk.gasSponsorship.gasSponsorshipPrepare({
        owner, chain,
        eip712: eip712 as any,
        signature,
        sender: sponsorAccount.address,
      });

      // Your sponsor signs and broadcasts — pays the gas
      const tx = sponsored.transaction as any;
      const sponsorWallet = createWalletClient({
        account: sponsorAccount, chain: viemChains[chain], transport: http(),
      });

      const hash = await sponsorWallet.sendTransaction({
        to: tx.to, data: tx.data,
        value: BigInt(tx.value || "0"),
        gas: tx.gas ? BigInt(tx.gas) : undefined,
        maxFeePerGas: BigInt(tx.maxFeePerGas),
        maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas),
      });

      await createPublicClient({ chain: viemChains[chain], transport: http() })
        .waitForTransactionReceipt({ hash });

      return Response.json({ success: true, txHash: hash });
    }
    ```
  </Tab>

  <Tab title="Frontend">
    ```typescript theme={null}
    // components/FundAccount.tsx
    import { useWallet } from "@getpara/react-sdk";
    import { useSignTypedData, useSwitchChain } from "wagmi";

    export function FundAccount() {
      const { data: wallet } = useWallet();
      const { signTypedDataAsync } = useSignTypedData();
      const { switchChainAsync } = useSwitchChain();

      async function fund(token: string, amount: string) {
        await switchChainAsync({ chainId: 8453 }); // Base

        // 1. Get EIP-712 typed data from your backend
        const prepareRes = await fetch("/api/transfer/prepare", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            owner: wallet?.address, chain: "base",
            token, amount,
          }),
        });
        const { eip712, normalizedTypes, primaryType, domain, message } =
          await prepareRes.json();

        // 2. Para wallet signs (user sees structured data, not hex)
        const signature = await signTypedDataAsync({
          domain, types: normalizedTypes,
          primaryType,
          message,
        });

        // 3. Your backend submits via gas sponsor
        await fetch("/api/execute", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            owner: wallet?.address,
            eip712, signature, chain: "base",
          }),
        });
      }

      return (
        <button onClick={() => fund("USDC", "100")}>
          Fund Earn Account with 100 USDC
        </button>
      );
    }
    ```
  </Tab>
</Tabs>

Every Compass operation — deposit, withdraw, swap, borrow, repay, bundle — follows this same three-step pattern. Only the SDK call in the **Prepare** step changes. The **Execute** route is reused by all operations.

<Warning>
  **Before your first gas-sponsored transfer**, each token needs a one-time [Permit2 approval](https://docs.compasslabs.ai/v2/api-reference/gas-sponsorship/approve-token-transfer). Without it, `earnTransfer` and `creditTransfer` will return an "Insufficient allowance" error.
</Warning>

```typescript theme={null}
// app/api/approve-transfer/route.ts
import { CompassApiSDK } from "@compass-labs/api-sdk";

export async function POST(request: Request) {
  const { owner, chain, token } = await request.json();

  const sdk = new CompassApiSDK({
    apiKeyAuth: process.env.COMPASS_API_KEY,
  });

  const approval = await sdk.gasSponsorship.gasSponsorshipApproveTransfer({
    owner, chain, token,
    gasSponsorship: true,
  });

  const eip712 = approval.eip712;

  // If no EIP-712 data, the token is already approved
  if (!eip712) {
    return Response.json({ approved: true });
  }

  const normalizedTypes = {
    EIP712Domain: (eip712.types as any).eip712Domain,
    Permit: (eip712.types as any).permit,
  };

  return Response.json({
    eip712, normalizedTypes,
    primaryType: eip712.primaryType,
    domain: eip712.domain,
    message: eip712.message,
  });
}
```

The frontend signing and execution flow is identical — use the same `signTypedDataAsync` and `/api/execute` calls shown above.

<Tip>
  Some tokens like USDT and WETH don't support EIP-2612 permits. For those, set `gasSponsorship: false` in the approve call — the user signs and pays gas for the one-time approval directly.
</Tip>

## Product Operations

The signing pattern is identical across all products. Only the SDK call in the **Prepare** step changes — swap it in and use the same **Execute** route and frontend signing flow from Step 3. Product operations return `SafeTx` types (normalize with `EIP712Domain` + `SafeTx`), unlike transfers which use `PermitTransferFrom`. The backend returns `primaryType` so the frontend handles both automatically.

<Tabs>
  <Tab title="Earn">
    ### Deposit into a Vault

    ```typescript theme={null}
    const deposit = await sdk.earn.earnManage({
      owner, chain,
      venue: { type: "VAULT", vaultAddress },
      action: "DEPOSIT",
      amount: "100",
      gasSponsorship: true,
    });
    // → returns eip712 → sign → execute
    ```

    ### Withdraw with Fee

    ```typescript theme={null}
    // You collect fees atomically — no separate payment flow
    const withdraw = await sdk.earn.earnManage({
      owner, chain,
      venue: { type: "VAULT", vaultAddress },
      action: "WITHDRAW",
      amount: "ALL",
      gasSponsorship: true,
      fee: {
        recipient: "0xYOUR_FEE_ADDRESS",
        amount: "10",
        denomination: "PERFORMANCE", // 10% of realized profit
      },
    });
    // → returns eip712 → sign → execute
    ```

    ### Check Positions

    ```typescript theme={null}
    // Read positions — no signing required
    const positions = await sdk.earn.earnPositions({
      owner: walletAddress,
      chain: "base",
    });
    // Returns: balance, PnL, yield earned, fee history
    ```
  </Tab>

  <Tab title="Credit">
    ### Borrow

    ```typescript theme={null}
    // Borrow USDC against deposited collateral via Aave V3
    const borrow = await sdk.credit.creditBorrow({
      owner, chain,
      borrowToken: "USDC",
      borrowAmount: "1000",
      gasSponsorship: true,
    });
    // → returns eip712 → sign → execute
    ```

    ### Repay Debt

    ```typescript theme={null}
    const repay = await sdk.credit.creditRepay({
      owner, chain,
      repayToken: "USDC",
      repayAmount: "1000",
      gasSponsorship: true,
    });
    // → returns eip712 → sign → execute
    ```

    ### Supply Collateral

    ```typescript theme={null}
    // Supply WETH as collateral on Aave via Credit Account
    const supply = await sdk.credit.creditBundle({
      owner, chain,
      gasSponsorship: true,
      actions: [
        {
          body: {
            actionType: "CREDIT_SUPPLY",
            token: "WETH",
            amount: "1.0",
          },
        },
      ],
    });
    // → returns eip712 → sign → execute
    ```

    ### Withdraw Collateral

    ```typescript theme={null}
    // Withdraw WETH collateral from Aave
    const withdraw = await sdk.credit.creditBundle({
      owner, chain,
      gasSponsorship: true,
      actions: [
        {
          body: {
            actionType: "CREDIT_WITHDRAW",
            token: "WETH",
            amount: "0.5",
          },
        },
      ],
    });
    // → returns eip712 → sign → execute
    ```

    ### Check Positions

    ```typescript theme={null}
    // Read positions — no signing required
    const creditHealth = await sdk.credit.creditPositions({
      owner: walletAddress,
      chain: "base",
    });
    // Returns: healthFactor, collateral, debt, LTV
    ```
  </Tab>

  <Tab title="Portfolio Manager">
    ### Rebalance Across Vaults

    ```typescript theme={null}
    // Atomic: withdraw → swap → deposit in one signature
    const bundle = await sdk.earn.earnBundle({
      owner, chain,
      gasSponsorship: true,
      actions: [
        {
          body: {
            actionType: "V2_MANAGE",
            venue: { type: "VAULT", vaultAddress: "0xVaultA..." },
            action: "WITHDRAW", amount: "ALL",
          },
        },
        {
          body: {
            actionType: "V2_SWAP",
            tokenIn: "USDC", tokenOut: "WETH",
            amountIn: "5000", slippage: 0.5,
          },
        },
        {
          body: {
            actionType: "V2_MANAGE",
            venue: { type: "VAULT", vaultAddress: "0xVaultB..." },
            action: "DEPOSIT", amount: "ALL",
          },
        },
      ],
    });
    // → returns eip712 → sign → execute
    ```

    Bundle any combination of withdrawals, swaps, and deposits into a single atomic transaction. If any step fails, the entire bundle reverts — no partial state.
  </Tab>
</Tabs>

## Querying Data

All read endpoints are free, require no signing, and return instantly. Use these to populate your UI with available markets and rates.

```typescript theme={null}
const sdk = new CompassApiSDK({ apiKeyAuth: process.env.COMPASS_API_KEY });

// List top vaults by TVL on Base
const vaults = await sdk.earn.earnVaults({
  orderBy: "tvl_usd", direction: "desc",
  chain: "base", assetSymbol: "USDC", limit: 10,
});
// Returns: vault address, APY, TVL, underlying asset, protocol

// List Aave lending markets with supply/borrow APYs
const aaveMarkets = await sdk.earn.earnAaveMarkets({ chain: "base" });

// List Pendle markets with implied APY and expiry
const pendleMarkets = await sdk.earn.earnPendleMarkets({
  orderBy: "tvl_usd", direction: "desc",
  chain: "base", limit: 10,
});
```

See the full [Compass API reference](https://docs.compasslabs.ai/v2/api-reference) for all available endpoints.

## Related Resources

<CardGroup cols={3}>
  <Card title="Compass Earn Docs" icon="vault" href="https://docs.compasslabs.ai/v2/Products/Earn">
    Vaults, APYs, and yield strategies across Morpho, Aave, and Pendle
  </Card>

  <Card title="Gas Sponsorship" icon="gas-pump" href="https://docs.compasslabs.ai/v2/Products/gas-sponsorship">
    Gasless transactions with EIP-712 signing and sponsor wallets
  </Card>

  <Card title="EIP-712 Typed Data Signing" icon="file-signature" href="/v3/walkthroughs/eip712-typed-data-signing">
    Sign structured data using the EIP-712 standard with Para wallets
  </Card>
</CardGroup>
