# Introducing Enclave Money

A brief overview of Enclave

## Overview

Enclave Money is the operating system for crypto and the new age financial internet. We've built an integrated account model that encapsulates asset ownership and abstraction, providing users access to crypto in the most simple yet efficient manner possible.

Think of Enclave as the layer that makes crypto feel as intuitive as the traditional web, while maintaining all the power and flexibility of decentralized finance.

Enclave is your gateway to the simplest and most efficient way to transact on chain. Enclave is building a chain-abstracted liquidity infrastructure and wallet designed to provide users with seamless access to decentralized applications.&#x20;

With Enclave SDK/APIs, your users can spend your assets across chains as if they were all consolidated on the same chain. This enables a completely chainless experience for the end-user bridging the gap between the UX of crypto applications and the UX of web2 applications that user's are familiar with today.

## How does it work?

#### Integrated Account Model

Enclave's integrated account model encapsulates asset ownership and abstraction in a single, powerful interface. Your assets, identity, and permissions are unified across the entire crypto ecosystem.

**Benefits:**

* Single source of truth for all your crypto assets
* Unified security model across applications
* Seamless cross-chain asset management

Enclave supports multiple blockchain networks, ensuring flexibility and broad access to crypto applications. Our innovative approach abstracts the complexities of interacting with different chains, offering a user-friendly experience that focuses on eliminating network and infrastructure specific complexities . By simply depositing assets into their account, end-users are able to instantly spend these assets on the chain of their choice. Enclave is powered by a meticulous orchestration of infrastructure that enables your users to:

* Transact instantly on any chain
* Transact on multiple chains without bridging
* Transact without paying for gas fees

## What can you achieve with Enclave Money?

* **Balance Abstraction:** Enable users to spend their fragmented balance on any chain in a single atomic transaction with 0 bridge latency. For example, a user with 10 USDC on Arbitrum, Optimism and Base can spend up to 30 USDC on ETH mainnet in a single atomic transation without bridging. The fragmented balance is treated as a single unified balance of 30 USDC. To the end-user it essentially feels like transacting on a single chain.
* **Gas Abstraction**: Enable users to transact on networks without paying for gas using native gas tokens. This can be done by either sponsoring the gas for their transaction, allowing users to pay in the token of their choice or allowing users to pay for gas using funds on a different network. For example:
  * User can pay for a transaction on Base using USDC on Base
  * User can pay for a transaction on Optimism using USDC on Base
* **Asset Abstraction:** Enable fungibility between tokens representing the same asset. There are several representations of the same asset which enhances liquidity fragmentation and leads to a very complex user experience. For example there are many assets representing the US dollar: USDC, USDT, DAI, USDe, PYUSD, etc. There are also many assets representing Bitcoin: WBTC, cbBTC, solvBTC, etc. These tokens all represent the same asset and have the same features (ex. none of them are yield bearing or produce any additional benefits that differentiate them from one another). Enclave can enable fungibility between these assets.&#x20;
  * A user can lend their funds to a USDT pool on Binance Smart Chain (which doesn't have USDC) and pay for this using USDC that they hold on Base. The user is not required to hold any USDT on BSC in this case but still has access to all the stablecoin based DeFi products on Binance Smart Chain.


# Enclave Smart Accounts

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2Fuka2uUz90L0rsEyNLzju%2FDiagrams%20-%20Frame%2025.jpg?alt=media&amp;token=fed11957-9895-45b2-86c1-1734efc3a33b" alt=""><figcaption></figcaption></figure>

## Flexible Account Ownership

Choose the account ownership structure that works best for you:

**Biometric-Based Wallet**

* Secure authentication using your unique biometric data
* No seed phrases to manage or lose
* Instant access with fingerprint, face, or voice recognition

**EOA-Based Wallet**

* Bring your existing Ethereum, Solana or Bitcoin wallets
* Maintain full control of your private keys
* Compatible with MetaMask, Ledger, and other popular wallets

**Social Authentication**

* Sign in with Google, Apple, Twitter, or other social accounts
* Secure key management handled behind the scenes

## Network and Gas Abstraction

We abstract away the complexity of different networks, gas fees, and cross-chain interactions.

**Features:**

* **Gas Fee Abstraction**: Pay fees in any token or have them sponsored
* **Multi-Chain Operations**: Seamless interactions across EVM, Solana and Bitcoin
* **Automatic Route Optimization**: Best execution across chains and protocols
* **Unified Balance View**: All your assets from all chains in one place

## Embedded Crypto Functionality

Enclave embeds crypto functionality directly into any interface, mobile or web. Developers can integrate powerful crypto features without building blockchain infrastructure from scratch.

**For Users:**

* Native crypto features in familiar apps
* No need to switch between multiple wallets
* Consistent experience across platforms

**For Developers:**

* Simple APIs to add crypto functionality
* No blockchain expertise required
* Focus on user experience, not infrastructure

## Intelligent Automation Engine

Enclave's automation engine uses permissioned session keys to execute sophisticated trading strategies and conditional operations without requiring constant user interaction.

**Permissioned Session Keys:**

* Granular permissions for specific actions and conditions
* Time-bounded and scope-limited access
* Secure delegation without compromising account control
* Revocable and updatable permission sets

**Automation Triggers:**

* **Price-Based Execution**: Automatically execute trades when assets hit target prices
* **Custom On-Chain Events**: React to specific smart contract events, governance proposals, or protocol changes
* **Wallet Mirroring**: Follow trades from specified wallets or copy successful strategies
* **Time-Based Actions**: Schedule recurring transactions or time-sensitive operations
* **Portfolio Rebalancing**: Maintain target allocations automatically

**Advanced Trading Features:**

* **Dollar Cost Averaging (DCA)**: Automated recurring purchases at set intervals
* **Limit Orders**: Buy/sell orders that execute when price conditions are met
* **Stop Loss/Take Profit**: Risk management orders that trigger automatically
* **Yield Optimization**: Automatically move funds to highest-yielding opportunities

## Custom Bundlers and Paymasters

Enclave leverages custom bundlers and paymasters to support low-cost transaction fees and the ability to pay for transactions in stablecoins or any other sufficiently liquid ERC20 token. This means users do not need to maintain any balances in the native tokens of the networks they are using. By allowing transactions to be paid in stablecoins, Enclave reduces friction and enhances convenience for users, ensuring they can interact with on-chain contract without worrying about network token balances.


# Security & Recovery

Enclave Money prioritizes the security and privacy of user accounts by incorporating advanced security features into its wallet infrastructure. These features ensure that users can safely manage their assets while maintaining control and privacy. Here are the key security features of Enclave Money wallets:

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2FwIW6J0dNzeLivnnUIxB8%2FGitbook%20Diagrams%20-%20Frame%205%20(2).jpg?alt=media&amp;token=c9829dc4-94b8-4296-8bd7-38d747a1e5cb" alt="" width="375"><figcaption></figcaption></figure>

* **Resilient Control**: In the event that Enclave's infrastructure is compromised or offline, users still have access to their accounts through their passkeys.
* **Account Recovery**: If a user loses their device, they can still recover their account using their passkey backups stored to iCloud keychain or Android's Credential Manager.

These security features, combined with Enclave Money's robust smart contract infrastructure, provide users with a secure and private way to manage their assets and engage with DeFi opportunities across multiple networks.

### Passkey-Based Authentication and Recovery

Enclave Money uses passkey-based authentication and recovery, powered by device-stored passkeys. This approach enhances security by leveraging the inherent security features of modern devices, such as biometric authentication or secure enclave storage. Passkeys provide a secure and user-friendly way to access and recover accounts without relying on traditional password systems, reducing the risk of unauthorized access.

### Zero-Knowledge Multi-Signature Recovery

To protect the privacy of account guardians and prevent collusion, Enclave Money employs zero-knowledge multi-signature recovery. This method ensures that the identities and actions of account guardians remain private, even during the recovery process. By using zero-knowledge proofs, Enclave Money can verify the authenticity of recovery requests without revealing any sensitive information, thereby safeguarding user privacy and preventing potential collusion among guardians.

These security features, combined with Enclave Money's robust smart contract infrastructure, provide users with a secure and private way to manage their assets and engage with DeFi opportunities across multiple networks.

<br>


# MEV Protection

Enclave smart accounts leverage secure enclaves to ensure that users’ transaction data remains private and tamper-resistant during execution, protecting them against MEV exploits. By integrating with [buildernet](https://buildernet.org/docs/how-to-participate), these accounts can safely route transactions through confidential block building infrastructure for guaranteed MEV protection.


# Enclave Money Protocol

Understanding the inner workings of Enclave

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2FEpfr0jSBnhLbB7ixo717%2FEnclave%20USD%20-%20CAB03.drawio.png?alt=media&amp;token=a5116e07-c38c-44b5-ab05-472eb109958a" alt=""><figcaption></figcaption></figure>

## Vaults

Vaults are open-source custom paymaster contracts (ERC 4337) that manage funds and fulfill requests for accessing funds on the desired target network. When a user wants to transact on a network where they don't have funds without bridging, they can borrow funds from the vault. This requires users to have an equal amount of funds or more on the vaults on the other chains. In order to access these funds the user's wallet submits a signature signed by the vault manager (or authorized signer for the paymaster).&#x20;

The paymaster verifies signatures and communicates settlement plans to the middleware for settlement based on the amount lent to the user for powering the user's desired action. The paymaster is managed by a vault manager that could be a 3rd party solver.

**For example:**\
If a user has 100 USDC on Arbitrum, 100 USDC on Optimism and 100 USDC on Base they can withdraw upto 300 USDC\* on any supported network. If the user wants to buy an NFT on Base worth 250 USDC, they can withdraw 250 USDC from the vault. 100 USDC withdrawn from the vault is deducted from the user's balance on Base and the remaining 150 USDC is lent by the vault to the user. Once the user's transaction is executed the cross chain settlement process is initiated which deducts 50 USDC and 100 USDC from the user's balances on Arbitrum and Optimism.

## Cross-Chain Communication

The messaging layer is used for transaction settlement. When a user's transaction is sponsored, the transaction needs to be settled by deducting from the user's balance on the chains where they do have funds. This settlement plan (mapping of chainId to debit amount) is encoded within the paymaster signature. When the required funds are transferred to the user, a message is sent to each chain in the settlement plan. The corresponding vault on the receiving chain receives this message and deducts the user's balance accordingly. Enclave uses Socket for managing cross-chain settlement (<https://socket.tech>).

## Bridging and Rebalancing

Bridging protocols are used to rebalance vault liquidity between chains. The rebalancer services is responsible for managing bridging and liquidity between networks. Enclave uses Socket's Bungee (<https://bungee.exchange>) protocol APIs for rebalancing liquidity between chains.

Funds are rebalanced across the different chains based on transaction demand.

## Intent Solver Marketplace

Intent solver marketplace is a network of solvers and a decentralised intent-pool that serves as an orderbook for matching user intents and solver bids.  This system will be upgraded over time by onboarding multiple solvers, decentralizing the intent pool, incorporating economic incentives (ex. staking / AVS) and optimizing for the following:

* Resilience - No single point of failure
* Availability - User intents must be matched with a solver bid
* Latency - User intents must be solved within a threshold time period

Solvers failing to meet the tenets of the system will be met with economic penalties (ex. slashing)

Enclave APIs are used to communicate with such solver networks.

## Indexer

Enclave maintains sophisticated low latency indexing infrastructure to support all the components of the system mentioned earlier. Managing virtual balances for cross chain assets supported by Enclave demands accurate and real-time synchronization of transaction states on all supported networks.

Enclave indexes all transfers, vault deposits, vault withdrawals and sponsored transactions to build a comprehensive real-time index and balance state for ensuring the secure and efficient functioning of the components that constitute the Enclave Money protocol.


# Asset Support

Enclave SDK and APIs are currently designed to support a variety of assets. Currently, Enclave supports deposits in USDC.

## Future Support

Enclave Money has plans to expand its API support to other blue chip multi-chain assets such as ETH, WETH, USDT, DAI, USDe, BTC and more.&#x20;


# Network Support

Enclave is designed to enable users to access the best opportunities across multiple blockchain networks. We are committed to expanding our network-support to ensure users can benefit from instant transactions on the networks of their choosing. Our rollout plan includes the following phases:

## Current Supported Networks

* **EVM L2 Networks:** Arbitrum, Optimism, Base

## Up Next

* EVM Mainnet
* Solana and SVM chains
* Remaining EVM L2s
* Alternative EVM L1s&#x20;
  * Avalanche
  * Monad
  * Movement
  * Etc

## Future Support

* MoveVM (Aptos and Sui)

By supporting a broad range of networks, Enclave Money ensures users can take advantage of the best yield sources available across the blockchain ecosystem, maximizing their returns while maintaining flexibility and accessibility.


# Wallet Support

The Enclave Money platform provides comprehensive support for various wallet types, enabling chain abstraction and seamless user experiences across different wallet implementations.

## Supported Wallet Types

### Embedded Wallets

Enclave Money SDK seamlessly integrates with popular embedded EOA wallet providers such as:

* Privy
* Dynamic
* Turnkey
* Web3Auth

These embedded wallets can be used in conjunction with the Enclave Money JS SDK to create chain-abstracted user experiences while maintaining familiar onboarding processes.

### Smart Contract Wallets

The Enclave Money SDK offers full compatibility with existing smart contract wallets. Developers can enable chain abstraction through:

1. **Session Key Access**:
   * Enables forwarding of user funds to Enclave paymaster vaults
   * Facilitates chain-abstracted balances spendable across any chain
   * Restricted specifically to fund forwarding operations
2. **Session Key Module Options**:
   * Developers can use their existing session key module
   * Alternatively, they can implement Enclave's ERC7579-compliant session key module

### Externally Owned Accounts (EOAs)

Enclave will soon enable advanced features for EOAs through EIP7702 implementation:

* Chain abstraction
* Transaction bundling
* Automated transaction execution
* Gasless transactions

This support extends to:

* Mobile/browser wallets (e.g., MetaMask, Rabby)
* Embedded wallet providers (e.g., Privy, Dynamic, Web3Auth, Turnkey)

Users can transact in a chain-abstracted manner by:

* Spending their asset balance on any chain
* Avoiding gas fees in native tokens
* Experiencing chainless crypto interactions

#### Demo

Here's a demo of a metamask EOA transacting on Odyssey testnet using funds on Arbitrum Sepolia and Optimism Sepolia

{% embed url="<https://www.loom.com/share/7a798ad0dd1a4fff9da9c86e3dc1ad02?sid=31883d51-20d0-4708-ae83-933464053ff6>" %}


# Magicspend++

Transact now, settle later!

## Overview

Normally, if a user wants to transact on a new chain, they need to:

1. Bridge tokens across chains
2. Manage gas on each chain
3. Wait for settlement before taking action

This creates friction, slows down activity, and reduces usability across chains.

**Magicspend++** lets users spend their token balances across multiple chains in one seamless transaction without bridging delays or worrying about gas fees:

* No bridging needed – funds are instantly available on the target chain
* No gas headaches – gas fees are sponsored
* Fast transactions – executed at the speed of the destination chain

## How it works

**Magicspend++** removes this friction with a borrow-and-settle model:

1. Resource Lock
   * Locks part of the user’s tokens on source chains.
   * Those funds can’t be spent elsewhere until settlement.
   * Enforced differently depending on wallet type:
     * **Turnkey Signers:** [Turnkey policies](https://docs.turnkey.com/concepts/policies/overview) prevent wallets from spending locked tokens.
     * **Privy Authorized Keys and Policies**:  [Privy policies](https://docs.privy.io/controls/policies/overview) prevent wallets from spending locked tokens.
     * **Smart contract wallets (e.g. Safe)**: Co-signer must approve spending of locked tokens.
2. Enclave Vault
   * Instantly lends tokens on the target chain so the user can transact right away.
   * The loan is repaid later using the locked funds across chains.

### Example

Let's say the user wants to buy 10 GMX tokens on Arbitrum but only has funds on Optimism and Base.

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2FrvGwniA2YUkhotCcQy4x%2FMagicspend%2B%2B(1).jpg?alt=media&amp;token=a207cc8c-b1d8-4a9d-a574-e74d37ddd8af" alt=""><figcaption></figcaption></figure>

**Magicspend++ flow:**

1. Borrow USDC on Arbitrum vault
2. Instantly swap on Arbitrum DEX
3. Settlement takes place later and deducts from Base and Optimism

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2FOgUZxKQbkXOY8Q0L7Ugc%2FMagicspend%2B%2B(2).jpg?alt=media&amp;token=5e5499e1-1cc5-4229-ba61-7ad1e98cc662" alt=""><figcaption></figcaption></figure>

### Wallet Support

Enclave supports Magicspend++ with the following wallet types:

1. Turnkey EOA Wallets
2. Privy EOA Wallets
3. Smart Contract Wallets (ERC4337, ERC7579 Smart Accounts)

### Batched Transactions and Gas Abstraction

Enclave leverages ERC4337 paymasters to abstract gas for users. ERC4337 /7579 accounts are also able to execute batched transactions which allows the end user to borrow from Enclave's vault and execute the desired action (ex. swap on Uniswap) in a single atomic on-chain transaction.

**EOA Support**

In order to support Turnkey EOAs, Enclave leverages EIP7702 to convert the EOA into a smart contract wallet, allowing it to inherit the properties of a smart contract wallet which supports gas sponsorship and transaction batching.

### Quote Types

#### Amount In

User specifies **exactly how much to spend** (inclusive of fees).&#x20;

For example: User wants to spend exactly $10 to buy a memecoin.

Enclave gives **$9.90 on target chain, settles $10 across balances** on other chains.

#### Amount Out

User specifies **how much they need on the target chain**

For example: User needs $10 on Base to lend on Morpho

Enclave gives **$10 on target chain**, **settles $10.10 across balances** on other chains.

{% hint style="info" %}
**Note on fees:** The quote includes fees for both the borrow cost as well as sponsoring the gas fees to be paid on the target chain for execution of the user's desired action, and the gas fees to be paid on the settlement chains for settlement transactions.
{% endhint %}


# Getting Started with Privy

Let's get started with a basic example using Privy

## Pre-requisites

### 1. Set Up Authorization Keys

**What is an authorization key?**

The authorization key is a user created by you, the client application, for the Enclave team, that allows us to issue transaction policies that enforce resource locks on users that wish to enable Magicspend++.

You can create an authorization key on the Privy dashboard by following the steps mentioned [here](https://docs.privy.io/controls/authorization-keys/keys/create/key).

Once you have created the authorization key, share the all key details with the Enclave team to enable integration. Also note down it's public key and API key name, these values are required for the next step.

### 2. Creating Users and Wallets with Key Quorums

Modify the existing user creation logic in your onboarding flow to provision a wallet with a key quorum that includes both the end user and the authorization key created in the previous step.&#x20;

The key quorum structure is such that each unique user has a wallet owned by a key quorum with 2 members: the end user and the authorization key that issues policies on the user's wallet.&#x20;

Given below is some sample code that can be used as reference:

#### Creating a wallet with authorization key

```javascript
import { usePrivy } from '@privy-io/react-auth';

const WalletComponent = () => {
    const { getAccessToken, authenticated } = usePrivy();
    
    const authPublicKey = process.env.NEXT_PUBLIC_ENCLAVE_AUTH_PUBLIC_KEY!;
    
    if (!authPublicKey) {
        console.log('⚠️ Authorization key not found in environment variables, skipping');
        return;
    }

    const createWalletWithQuorum = async (chainType: 'ethereum' | 'solana') => {
        const token = await getAccessToken();
        
        const response = await fetch('/api/wallets/create', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`,
            },
            body: JSON.stringify({ chainType }),
        });
        
        const result = await response.json();
        return result.wallet;
    };
};
```

#### Server-side implementation

```javascript
import { usePrivy } from '@privy-io/react-auth';

const WalletComponent = () => {
    const { getAccessToken, authenticated } = usePrivy();
    
    const authPublicKey = process.env.NEXT_PUBLIC_ENCLAVE_AUTH_PUBLIC_KEY!;
    
    if (!authPublicKey) {
        console.log('⚠️ Authorization key not found in environment variables, skipping');
        return;
    }

    const createWalletWithQuorum = async (chainType: 'ethereum' | 'solana') => {
        const token = await getAccessToken();
        
        const response = await fetch('/api/wallets/create', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`,
            },
            body: JSON.stringify({ chainType }),
        });
        
        const result = await response.json();
        return result.wallet;
    };
};

Server-side implementation
import { NextResponse } from 'next/server';
import { getAccessTokenFromRequest, verifyAccessToken } from '@/lib/privy-server';

const PRIVY_APP_ID = process.env.NEXT_PUBLIC_PRIVY_APP_ID;
const PRIVY_APP_SECRET = process.env.NEXT_PUBLIC_PRIVY_APP_SECRET;
const PRIVY_AUTHORIZATION_PUBLIC_KEY = process.env.PRIVY_AUTHORIZATION_PUBLIC_KEY;
const PRIVY_API_URL = 'https://api.privy.io/v1';

export async function POST(request: Request) {
    // Extract and verify token
    const token = getAccessTokenFromRequest(request);
    if (!token) {
        return NextResponse.json({ error: 'No access token' }, { status: 401 });
    }

    const claims = await verifyAccessToken(token);
    if (!claims) {
        return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
    }

    const userId = claims.userId;
    const { chainType } = await request.json();

    // Format public key
    const formattedPublicKey = PRIVY_AUTHORIZATION_PUBLIC_KEY!.replace(/\\n/g, '\n');
    
    // Create 1-of-2 key quorum
    const keyQuorumResponse = await fetch(`${PRIVY_API_URL}/key_quorums`, {
        method: 'POST',
        headers: {
            'Authorization': `Basic ${Buffer.from(`${PRIVY_APP_ID}:${PRIVY_APP_SECRET}`).toString('base64')}`,
            'privy-app-id': PRIVY_APP_ID!,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            public_keys: [formattedPublicKey],
            user_ids: [userId],
            authorization_threshold: 1,
        }),
    });

    const keyQuorum = await keyQuorumResponse.json();
    
    // Create wallet owned by key quorum
    const walletResponse = await fetch(`${PRIVY_API_URL}/wallets`, {
        method: 'POST',
        headers: {
            'Authorization': `Basic ${Buffer.from(`${PRIVY_APP_ID}:${PRIVY_APP_SECRET}`).toString('base64')}`,
            'privy-app-id': PRIVY_APP_ID!,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            chain_type: chainType,
            owner_id: keyQuorum.id,
        }),
    });

    const wallet = await walletResponse.json();
    
    return NextResponse.json({
        success: true,
        wallet: {
            id: wallet.id,
            address: wallet.address,
            chainType: wallet.chain_type,
        }
    });
}


```

**Next let's see how we can fetch a quote**

{% content-ref url="/pages/yF53uosJVEmnhVmpuUcx" %}
[Fetching a quote](/introducing-enclave-money/magicspend++/getting-started-with-turnkey/fetching-a-quote)
{% endcontent-ref %}


# Fetching a quote

Let's fetch a quote for executing a chain abstracted batch of transactions

Fetching a quote requires the client to specify the following inputs:

1. **walletAddress:** The user's EVM or Solana wallet address
2. **chainId**: Chain ID of the target chain
3. **amount:** How much they want to spend on the target chain
4. **type:** The type of quote the user is fetching. Learn more about quote types [here](https://docs.enclave.money/introducing-enclave-money/magicspend++#quote-types).
5. **settlementToken:** The token the user will settle in (ex. USDC or SOL)
6. **spendingTokenAddress:** The token the user wants to borrow and spend on the target chain
7. &#x20;**transactions:** A list of transaction objects representing the actions the user wants to execute on the target chain. These could be any type of transaction including transfers, swaps, depositing to yield protocols, buying an NFT, etc.

#### Importing libraries

```javascript
import axios from 'axios';
```

#### Defining types

```javascript
enum QuoteType {
  AMOUNT_IN = 'AMOUNT_IN',
  AMOUNT_OUT = 'AMOUNT_OUT'
}

type Transaction = {
  to: string;      // destination contract/address (0x-prefixed)
  data: string;    // calldata (0x-prefixed)
  value: string;   // value in wei (as string)
};

type GetQuoteParams = {
  // Solution inputs
  walletAddress: string;            // registered EVM address or Solana Address
  chainId: number;                  // chain ID
  amount: string;                   // smallest units, e.g. "200000" for 0.2 USDC
  type: QuoteType;                  // borrow mode (AMOUNT_IN or AMOUNT_OUT)
  settlementToken?: string | null;  // 'SOL' for SOL settlement, USDC by default
  spendingTokenAddress?: string | null;    // USDC by default, specify address of token on the chain corresponding to the given chainId

  // New: explicit call bundle the solver should execute
  transactions?: Transaction[]; // [{ to, data, value }, ...]
};

type QuoteResponse = type Quote = {
  chainId: number;
  tokenAddress: string;
  
  // Amount the user pays from source chains
  settlementAmount: string;
  
  // Expected amount of tokens the user will have on the target chain after borrowing
  expectedAmountOut: string;

  // Map of chain IDs to amounts to be settled from the corresponding chain
  settlementPlan: Record<string, string>;
};
```

#### Setting up request headers

```javascript
const headers = {
  'Content-Type': 'application/json',
  'Authorization': process.env.ENCLAVE_API_KEY,
};
```

#### Calling the quote API

<pre class="language-javascript"><code class="lang-javascript"><strong>export async function getQuote(params: GetQuoteParams): Promise&#x3C;QuoteResponse> {
</strong>  const {
    userId,
    walletAddress,
    outputNetwork,
    amount,
    type,
    settlementToken = null, // USDC by default
    spendingTokenAddress = null,   // USDC by default
    transactions = [],
  } = params;

  const { data } = await axios.post(
    `https://api.enclave.money/magicspend/quote`,
    {
      userId,
      walletAddress,
      outputNetwork,
      amount,
      type,
      settlementToken,
      spendingToken,
      transactions, // [{ to, data, value }]
    },
    {
      headers: headers
    }
  );
  
  const {
    expectedAmountOut,
    settlementAmount,
    settlementPlan
  } = data;
  
  console.log(`User receives: ${expectedAmountOut}`);
  console.log(`User pays: ${settlementAmount}`);
  console.log(`Payment split between networks: ${settlementPlan}`);

  return data
}
</code></pre>

{% hint style="info" %}
**Note on specifying spending amount:** The client specifies how much of a given token the user wants to spend. In the case where are user has 5$ on Base, but wants to lend a total of 10$ to a vault on Base, the client would set the amount field to 10$. Enclave will lend the user the 5$ deficit and fees will only be charged on the amount the user ends up borrowing.
{% endhint %}


# Executing a transaction

To demonstrate MagicSpend++, we'll walk through a simple, real-world EVM transaction: transferring 1.0 USDC on Polygon. This compact example shows the full flow end-to-end—constructing ERC‑20 transfer calldata from the USDC ABI, requesting a canonical userOp hash from the backend, signing that hash with a Privy-backed wallet, producing EIP‑7702 authorization(s), and finally submitting everything to a submit endpoint. By following this sequence, you'll see how MagicSpend++ enables chain abstracted execution with minimal friction while keeping the signer experience familiar.

### Step 1 — Build ERC‑20 Transfer Transaction Calldata

{% tabs %}
{% tab title="Viem" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>import { erc20Abi, encodeFunctionData, parseUnits } from 'viem';
</strong>
const chainId = 137;
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const recipient = '0x1111111111111111111111111111111111111111';

// 1. Convert 1.0 USDC to base units (6 decimals)
const amount = parseUnits('1.0', 6);

// 2. Encode transfer(to, amount) calldata
const encodedData = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'transfer',
  args: [recipient, amount],
});
</code></pre>

{% endtab %}

{% tab title="Ethers" %}

```javascript
import { Interface, parseUnits } from 'ethers';

const chainId = 137;
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const recipient = '0x1111111111111111111111111111111111111111';

const erc20 = new Interface([
  'function transfer(address to, uint256 amount) returns (bool)'
]);

const amount = parseUnits('1.0', 6); // 1 USDC -> 1_000_000
const encodedData = erc20.encodeFunctionData('transfer', [recipient, amount]);
```

{% endtab %}
{% endtabs %}

#### Step 2 — Build the chain abstracted transaction (with quote type + token addresses)

```javascript
import axios from 'axios';

const chainId = 137; // Polygon

// Token the user settles in
const settlementToken = 'USDC'; 

// Token the user spends
const spendingTokenAddress = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';

// For a transfer, spending and settlement tokens are both USDC.
// Use 'AMOUNT_OUT' to send an exact recipient amount; 'AMOUNT_IN' to spend an exact input amount.
const quoteType = 'AMOUNT_OUT'; // or 'AMOUNT_IN'
const amount = '1000000'; // Formatted amount (USDC uses 6 decimals)

const { data: transactionData } = await axios.post('https://api.enclave.money/magicspend/build-transaction', {
  chainId,
  transactions: [{
    to: usdc
    
    // encodedData comes from Step 1 (ERC-20 transfer calldata built via viem/ethers)
    data: encodedData
  }],
  quoteType, // 'AMOUNT_OUT' | 'AMOUNT_IN'
  amount, // '1.0' => 1 USDC
  spendingTokenAddress,   // token user spends
  settlementToken // token user settle in (ex. 'USDC' or 'SOL')
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': process.env.ENCLAVE_API_KEY,
  }
});

const { 
  userOpHash, 
  authorizations, 
  settlementPlan, 
  expiryTimestamp, 
  transactionId 
} = transactionData;
```

**Supported Settlement Tokens**

| Token | Identifier | Supported Networks                                                                                                 |
| ----- | ---------- | ------------------------------------------------------------------------------------------------------------------ |
| USDC  | USDC       | Ethereum Mainnet, Arbitrum, Base, Optimism, Polygon, Avalanche, Unichain, Binance Smart Chain, World Chain, Solana |
| SOL   | SOL        | Solana                                                                                                             |
| ETH   | ETH        | Ethereum Mainnet, Arbitrum, Base, Optimism, Polygon, Unichain, World Chain                                         |

### Step 3 — Initialize Privy and sign the user operation and authorizations

```javascript
import { PrivyClient } from '@privy-io/node';

// Initialize Privy client (equivalent to TurnkeyServerSDK)
const privyClient = new PrivyClient(
  process.env.NEXT_PUBLIC_PRIVY_APP_ID!,
  process.env.NEXT_PUBLIC_PRIVY_APP_SECRET!
);

// User's wallet ID from Privy (equivalent to Turnkey's organizationId + address)
const walletId = 'USER_WALLET_ID'; // Get this from the user's Privy embedded wallet

// Sign the userOpHash (equivalent to walletClient.signMessage)
const { signature: userOpSignature, encoding } = await privyClient
  .wallets()
  .ethereum()
  .signMessage(walletId, {
    params: {
      message: userOpHash
    }
  });
```

### Step 4 — Sign EIP‑7702 authorization(s)

```javascript
// Sign each authorization
const authorizationList = await Promise.all(
  authorizations.map((authorization: { contractAddress: string, chainId: number, nonce: bigint }) =>
    privyClient
      .wallets()
      .ethereum()
      .sign7702Authorization(walletId, {
        params: {
          contract: authorization.contractAddress,
          chainId: authorization.chainId,
          nonce: Number(authorization.nonce)
        }
      })
  )
);
```

### Step 5 - Submitting the transaction

```javascript
// Submitting transaction response
const { data: submitResponse } = await axios.post('https://api.enclave.money/magicspend/submit', {
  transactionId,
  userOpSignature,
  authorizationList,
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': process.env.ENCLAVE_API_KEY,
  }
});

const { txHash, transactionId, status } = submitResponse
```

### Step 6 - Checking the status of the transaction

```javascript
const { 
    status, 
    failureReason, 
    executedAt, 
    settledAt, 
    targetTransaction, 
    settlementTransactions  
} = await axios.get('https://api.enclave.money/magicspend/tx-status', 
    { params: { transactionId } },
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': process.env.ENCLAVE_API_KEY,
    }
});
// Example: { status: 'PENDING' | 'SUBMITTED' | 'TARGET_EXECUTED' | 'SETTLING | 'SETTLEMENT_EXECUTED' | 'EXPIRED' | 'FAILED' }
console.log('Transaction Status:', status);
```

**Status Codes**

| Status Code          | Description                                                                                                 |
| -------------------- | ----------------------------------------------------------------------------------------------------------- |
| PENDING              | Transaction is built but signatures for the transaction have not been submitted yet                         |
| SUBMITTED            | Transaction has been submitted and the user's desired action will be executed on the target chain           |
| TARGET\_EXECUTED     | Target chain transaction has been succeefully executed. Settlement of the transaction is now pending.       |
| SETTLING             | Settlement transactions on each of the settlement chains have been submitted and pending execution          |
| SETTLEMENT\_EXECUTED | Settlement transactions on all settlement chains have been executed                                         |
| EXPIRED              | Transaction was built but was not submitted on time for valid execution                                     |
| FAILED               | Transaction execution failed. This may be due to a reverted transaction on the target or settlement chains. |


# Getting Started with Turnkey

Let's get started with a basic example using Turnkey

## Pre-requisites

### 1. Create a delegate user on the Turnkey dashboard

**What is a delegate user?**

A delegate user is a user created by you, the client application, for the Enclave team, that allows us to issue transaction policies that enforce resource locks on users that wish to enable Magicspend++.

You can create a delegate user on the Turnkey dashboard by following the steps mentioned [here](https://docs.turnkey.com/concepts/policies/delegated-access).

Once you have created the delegate user, share the all delegate key details with the Enclave team to enable integration. Also note down it's public key and API key name, these values are required for the next step.

### 2. Creating users and sub-organizations

Modify the existing user creation logic in your onboarding flow to provision a unique sub organization for each user and add the delegate user created in the previous step to the sub organization.

The sub organization structure is such that each unique user has their own sub organization. Each sub organization has 2 users. The end user and the delegate user that issues policies on the end user's wallet.

Given below is some sample code that can be used as reference:

#### Adding a delegate user

```javascript
import { useTurnkey, AuthState } from '@turnkey/react-wallet-kit';
...

const LoginComponent = () => {
    const { authState, user, wallets, createWallet, refreshWallets, httpClient } = useTurnkey();
    ...
    
    const delegateApiKeyName = process.env.NEXT_PUBLIC_ENCLAVE_DELEGATE_API_KEY_NAME!;
    const delegatePublicKey = process.env.NEXT_PUBLIC_ENCLAVE_DELEGATE_PUBLIC_KEY!;
    
    if (!delegateApiKeyName || !delegatePublicKey) {
        console.log('⚠️ Delegate API credentials not found in environment variables, skipping');
        return;
    }

    console.log('📝 Adding delegate user to sub-organization...');

    const curveType: "API_KEY_CURVE_P256" = "API_KEY_CURVE_P256";
    
    const delegateApiKeys = [{
        apiKeyName: delegateApiKeyName,
        publicKey: delegatePublicKey,
        curveType,
    }];
    
    const fetchQuote = async () => {
        // Get the current organization info
        const orgInfo = await httpClient.getOrganization();
        const subOrgId = orgInfo?.organizationData?.organizationId;
            
        const response = await httpClient.createUsers({
            organizationId: subOrgId,
            users: [
                {
                    userName: "enclave_delegate_user",
                    userEmail: "delegate@enclave.money",
                    userTags: [],
                    apiKeys: delegateApiKeys,
                    authenticators: [],
                    oauthProviders: [],
                }
            ]
        });
    }
}


```

#### Adding a new end-user wallet

If the user logging in is a new user, then we create new EVM and Solana wallets for them within the same sub-org

```javascript
const { createWallet } = useTurnkey();

const walletId = await createWallet({
    walletName: `AutoWallet-${new Date().getTime()}`,
    accounts: ["ADDRESS_FORMAT_ETHEREUM", "ADDRESS_FORMAT_SOLANA"],
});
```

**Next let's see how we can fetch a quote**

{% content-ref url="/pages/yF53uosJVEmnhVmpuUcx" %}
[Fetching a quote](/introducing-enclave-money/magicspend++/getting-started-with-turnkey/fetching-a-quote)
{% endcontent-ref %}


# Fetching a quote

Let's fetch a quote for executing a chain abstracted batch of transactions

Fetching a quote requires the client to specify the following inputs:

1. **walletAddress:** The user's EVM or Solana wallet address
2. **chainId**: Chain ID of the target chain
3. **amount:** How much they want to spend on the target chain
4. **type:** The type of quote the user is fetching. Learn more about quote types [here](https://docs.enclave.money/introducing-enclave-money/magicspend++#quote-types).
5. **settlementToken:** The token the user will settle in (ex. USDC or SOL)
6. **spendingTokenAddress:** The token the user wants to borrow and spend on the target chain
7. &#x20;**transactions:** A list of transaction objects representing the actions the user wants to execute on the target chain. These could be any type of transaction including transfers, swaps, depositing to yield protocols, buying an NFT, etc.

#### Importing libraries

```javascript
import axios from 'axios';
```

#### Defining types

```javascript
enum QuoteType {
  AMOUNT_IN = 'AMOUNT_IN',
  AMOUNT_OUT = 'AMOUNT_OUT'
}

type Transaction = {
  to: string;      // destination contract/address (0x-prefixed)
  data: string;    // calldata (0x-prefixed)
  value: string;   // value in wei (as string)
};

type GetQuoteParams = {
  // Solution inputs
  walletAddress: string;            // registered EVM address or Solana Address
  chainId: number;                  // chain ID
  amount: string;                   // smallest units, e.g. "200000" for 0.2 USDC
  type: QuoteType;                  // borrow mode (AMOUNT_IN or AMOUNT_OUT)
  settlementToken?: string | null;  // 'SOL' for SOL settlement, USDC by default
  spendingTokenAddress?: string | null;    // USDC by default, specify address of token on the chain corresponding to the given chainId

  // New: explicit call bundle the solver should execute
  transactions?: Transaction[]; // [{ to, data, value }, ...]
};

type QuoteResponse = type Quote = {
  chainId: number;
  tokenAddress: string;
  
  // Amount the user pays from source chains
  settlementAmount: string;
  
  // Expected amount of tokens the user will have on the target chain after borrowing
  expectedAmountOut: string;

  // Map of chain IDs to amounts to be settled from the corresponding chain
  settlementPlan: Record<string, string>;
};
```

#### Setting up request headers

```javascript
const headers = {
  'Content-Type': 'application/json',
  'Authorization': process.env.ENCLAVE_API_KEY,
};
```

#### Calling the quote API

<pre class="language-javascript"><code class="lang-javascript"><strong>export async function getQuote(params: GetQuoteParams): Promise&#x3C;QuoteResponse> {
</strong>  const {
    userId,
    walletAddress,
    outputNetwork,
    amount,
    type,
    settlementToken = null, // USDC by default
    spendingTokenAddress = null,   // USDC by default
    transactions = [],
  } = params;

  const { data } = await axios.post(
    `https://api.enclave.money/magicspend/quote`,
    {
      userId,
      walletAddress,
      outputNetwork,
      amount,
      type,
      settlementToken,
      spendingToken,
      transactions, // [{ to, data, value }]
    },
    {
      headers: headers
    }
  );
  
  const {
    expectedAmountOut,
    settlementAmount,
    settlementPlan
  } = data;
  
  console.log(`User receives: ${expectedAmountOut}`);
  console.log(`User pays: ${settlementAmount}`);
  console.log(`Payment split between networks: ${settlementPlan}`);

  return data
}
</code></pre>

{% hint style="info" %}
**Note on specifying spending amount:** The client specifies how much of a given token the user wants to spend. In the case where are user has 5$ on Base, but wants to lend a total of 10$ to a vault on Base, the client would set the amount field to 10$. Enclave will lend the user the 5$ deficit and fees will only be charged on the amount the user ends up borrowing.
{% endhint %}


# Executing a transaction

To demonstrate MagicSpend++, we’ll walk through a simple, real-world EVM transaction: transferring 1.0 USDC on Polygon. This compact example shows the full flow end-to-end—constructing ERC‑20 transfer calldata from the USDC ABI, requesting a canonical userOp hash from the backend, signing that hash with a Turnkey-backed account, producing EIP‑7702 authorization(s), and finally submitting everything to a submit endpoint.&#x20;

By following this sequence, you’ll see how MagicSpend++ enables chain abstracted execution with minimal friction while keeping the signer experience familiar.

### Step 1 — Build ERC‑20 Transfer Transaction Calldata

{% tabs %}
{% tab title="Viem" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>import { erc20Abi, encodeFunctionData, parseUnits } from 'viem';
</strong>
const chainId = 137;
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const recipient = '0x1111111111111111111111111111111111111111';

// 1. Convert 1.0 USDC to base units (6 decimals)
const amount = parseUnits('1.0', 6);

// 2. Encode transfer(to, amount) calldata
const encodedData = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'transfer',
  args: [recipient, amount],
});
</code></pre>

{% endtab %}

{% tab title="Ethers" %}

```javascript
import { Interface, parseUnits } from 'ethers';

const chainId = 137;
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const recipient = '0x1111111111111111111111111111111111111111';

const erc20 = new Interface([
  'function transfer(address to, uint256 amount) returns (bool)'
]);

const amount = parseUnits('1.0', 6); // 1 USDC -> 1_000_000
const encodedData = erc20.encodeFunctionData('transfer', [recipient, amount]);
```

{% endtab %}
{% endtabs %}

#### Step 2 — Build the chain abstracted transaction (with quote type + token addresses)

```javascript
import axios from 'axios';

const chainId = 137; // Polygon

// Token the user settles in
const settlementToken = 'USDC'; 

// Token the user spends
const spendingTokenAddress = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';

// For a transfer, spending and settlement tokens are both USDC.
// Use 'AMOUNT_OUT' to send an exact recipient amount; 'AMOUNT_IN' to spend an exact input amount.
const quoteType = 'AMOUNT_OUT'; // or 'AMOUNT_IN'
const amount = '1000000'; // Formatted amount (USDC uses 6 decimals)

const { data: transactionData } = await axios.post('https://api.enclave.money/magicspend/build-transaction', {
  chainId,
  transactions: [{
    to: usdc
    
    // encodedData comes from Step 1 (ERC-20 transfer calldata built via viem/ethers)
    data: encodedData
  }],
  quoteType, // 'AMOUNT_OUT' | 'AMOUNT_IN'
  amount, // '1.0' => 1 USDC
  spendingTokenAddress,   // token user spends
  settlementToken // token user settle in (ex. 'USDC' or 'SOL')
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': process.env.ENCLAVE_API_KEY,
  }
});

const { 
  userOpHash, 
  authorizations, 
  settlementPlan, 
  expiryTimestamp, 
  transactionId 
} = transactionData;
```

**Supported Settlement Tokens**

| Token | Identifier | Supported Networks                                                                                                 |
| ----- | ---------- | ------------------------------------------------------------------------------------------------------------------ |
| USDC  | USDC       | Ethereum Mainnet, Arbitrum, Base, Optimism, Polygon, Avalanche, Unichain, Binance Smart Chain, World Chain, Solana |
| SOL   | SOL        | Solana                                                                                                             |
| ETH   | ETH        | Ethereum Mainnet, Arbitrum, Base, Optimism, Polygon, Unichain, World Chain                                         |

### Step 3 - Initialize turnkey and sign the user operation and authorizations

```javascript
import { Turnkey as TurnkeyServerSDK } from '@turnkey/sdk-server';
import { createAccount } from '@turnkey/viem';
import { createWalletClient, http } from 'viem';
import { polygon } from 'viem/chains';

const turnkeyClient = new TurnkeyServerSDK({
  apiBaseUrl: 'https://api.turnkey.com',
  apiPrivateKey: process.env.NEXT_PUBLIC_ENCLAVE_DELEGATE_API_PRIVATE_KEY!,
  apiPublicKey: process.env.NEXT_PUBLIC_ENCLAVE_DELEGATE_API_PUBLIC_KEY!,
});

const organizationId = 'USER_SUB_ORG_ID';
const userTurnkeyEvmAddress = '0xUserAddress';
const rpcUrl = '<YOUR_RPC_URL>';

const account = await createAccount({
  client: turnkeyClient.apiClient(),
  organizationId,
  signWith: userTurnkeyEvmAddress,
});

const walletClient = createWalletClient({
  account,
  chain: polygon,
  transport: http(rpcUrl),
});

const userOpSignature = await walletClient.signMessage({
  account: walletClient.account,
  message: { raw: userOpHash },
});
```

### Step 4 — Sign EIP‑7702 authorization(s)

```javascript
// Sign each authorization
const authorizationList = await Promise.all(
  authorizations.map((authorization: { contractAddress, chainId, nonce }) =>
    walletClient.signAuthorization({
      ...authorization,
      account: walletClient.account,
    })
  )
);
```

### Step 5 - Submitting the transaction

```javascript
// Submitting transaction response
const { data: submitResponse } = await axios.post('https://api.enclave.money/magicspend/submit', {
  transactionId,
  userOpSignature,
  authorizationList,
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': process.env.ENCLAVE_API_KEY,
  }
});

const { txHash, transactionId, status } = submitResponse
```

### Step 6 - Checking the status of the transaction

```javascript
const { 
    status, 
    failureReason, 
    executedAt, 
    settledAt, 
    targetTransaction, 
    settlementTransactions  
} = await axios.get('https://api.enclave.money/magicspend/tx-status', 
    { params: { transactionId } },
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': process.env.ENCLAVE_API_KEY,
    }
});
// Example: { status: 'PENDING' | 'SUBMITTED' | 'TARGET_EXECUTED' | 'SETTLING | 'SETTLEMENT_EXECUTED' | 'EXPIRED' | 'FAILED' }
console.log('Transaction Status:', status);
```

**Status Codes**

| Status Code          | Description                                                                                                 |
| -------------------- | ----------------------------------------------------------------------------------------------------------- |
| PENDING              | Transaction is built but signatures for the transaction have not been submitted yet                         |
| SUBMITTED            | Transaction has been submitted and the user's desired action will be executed on the target chain           |
| TARGET\_EXECUTED     | Target chain transaction has been succeefully executed. Settlement of the transaction is now pending.       |
| SETTLING             | Settlement transactions on each of the settlement chains have been submitted and pending execution          |
| SETTLEMENT\_EXECUTED | Settlement transactions on all settlement chains have been executed                                         |
| EXPIRED              | Transaction was built but was not submitted on time for valid execution                                     |
| FAILED               | Transaction execution failed. This may be due to a reverted transaction on the target or settlement chains. |


# Embedded Swaps

Embedded multi-chain swaps in 2 lines of code

#### Universal Swap Integration

Enclave's swap functionality can be embedded into any application with just a few lines of code. Our universal swap engine supports multiple virtual machines and provides the deepest liquidity across the entire crypto ecosystem.

**Multi-VM Support:**

* **EVM Chains**: Ethereum, Polygon, Arbitrum, Optimism, BSC, Avalanche, and 50+ other networks
* **Solana VM**: Native Solana token swaps with Jupiter aggregation
* **Bitcoin Network**: Lightning Network swaps and ordinals trading
* **Cross-VM Swaps**: Seamlessly trade between different blockchain ecosystems

**Integration Features:**

* **One-Line Integration**: Add swap functionality with a single SDK call
* **Customizable UI**: White-label swap interface that matches your app's design
* **Headless API**: Build custom interfaces with our swap engine
* **Real-Time Pricing**: Live price feeds and market data
* **Route Optimization**: Automatically find the best prices across all DEXs and chains

#### Monetization

Integrating applications can monetize their user base by earning a percentage of trading fees generated through embedded swap functionality. This creates a new, passive revenue stream that complements existing business models.

* **Fee Revenue**: Earn a cut of every swap transaction made through your application
* **No Additional User Cost**: Users pay standard market rates while you earn from volume
* **Scalable Income**: Revenue grows with your user base and trading activity
* **Zero Infrastructure**: No need to build or maintain trading infrastructure
* **Transparent Reporting**: Real-time analytics on trading volume and earned fees


# Unified Deposit Address

Onboard users from any chain with any asset

### Overview

Unified Deposit Address (UDA) is a cross-chain API solution that enables crypto applications to onboard users from any blockchain network using any supported asset. By providing a single deposit address deployed across multiple chains, UDA eliminates the friction of manual bridging and chain-specific asset requirements.

Traditional crypto applications face significant user acquisition challenges:

* **Chain Lock-in**: Users must bridge assets from different chains where they hold funds to the application's chain before they can start using the app
* **User Confusion**: Users often send incorrect assets to wrong addresses on incompatible chains and end up losing funds
* **Complex User Journey**: Multiple transactions and additional steps create friction in the onboarding process
* **Reduced Conversion**: Technical barriers like manual bridging prevent users from trying new apps

### Solution

UDA provides a **single, unified deposit address** deployed across multiple blockchain networks. When users send any supported asset to this address, the system automatically:

1. **Swaps** the deposited asset to the required token
2. **Teleports** the converted funds to the specified destination chain
3. **Delivers** the final asset to the user's wallet on the target network

### How It Works

#### Example

**Scenario**: Polymarket requires USDC on Polygon

* **User Holdings**: 10 USDT  on Avalanche
* **Action**: User simply transfers USDT to the unified deposit address
* **Result**: USDT is automatically converted to USDC and delivered to user's Polygon wallet

**Outcome:** User can immediately start trading on Polymarket without bridging or relying on third party applications to onboard to Polymarket.

### Supported Networks

| Network             | ID    |
| ------------------- | ----- |
| Ethereum            | 1     |
| Arbitrum            | 42161 |
| Base                | 8453  |
| Optimism            | 10    |
| Unichain            | 130   |
| Worldchain          | 480   |
| Binance Smart Chain | 56    |
| Avalanche           | 43114 |
| Polygon             | 137   |
| Sonic               | 146   |

#### Coming Soon

|         |           |
| ------- | --------- |
| Solana  | 792703809 |
| Bitcoin | 8253038   |

### Start Integrating

Get started by creating an account and getting your API key at [portal.enclave.money](https://portal.enclave.money/) and following the API documentation below:

{% content-ref url="/pages/dnej6tvQTN7AW1FbOQVe" %}
[Unified Deposit Address](/integrate-with-enclave-money/api-reference/unified-deposit-address)
{% endcontent-ref %}


# Virtual Liquidity Balance and Transaction Flow

## Deposit

Users deposit funds by interfacing with the vault contract of the VLL. Once a user deposits their tokens into a vault on any supported network, their virtual balance is updated proportionately and they can spend their entire virtual balance on any supported network.

```
A - user's wallet address
T - Given token represented by token symbol (ex. USDC)
deposit(i, T, A) - Current deposit value of token in vault on chainId(i) for given user address
networks(T) - set representing the list of supported networks where token T is deployed
vb(A, T) - Virtual balance of a user's address for a given token
```

$$
vb(A,T) = \sum\_{i} deposit(i, T, A)  |  i  \in networks(T)
$$

## Transaction Execution

User's can claim/withdraw funds from the VLL to execute their desired transactions. Let's walk through an example transaction. Assume a user has a virtual USDC balance equal to 400. Given below is a table describing the state of the user deposits across networks constituting the user's virtual balance.

<table><thead><tr><th>Network</th><th>User USDC Deposit</th><th data-hidden>ChainId</th></tr></thead><tbody><tr><td>Ethereum</td><td>100</td><td>1</td></tr><tr><td>Base</td><td>200</td><td>8453</td></tr><tr><td>Arbitrum</td><td>100</td><td></td></tr></tbody></table>

Let's assume a user wants to purchase an NFT on Base and the cost of the NFT is 350 USDC.&#x20;

The user's balance on Base is 200 USDC and deficit is 150 USDC.

### Intent

The user's desired transaction requirements can be expressed as an intent. The user's intent in the example given above is to spend 350 USDC from their VLL balance, i.e, the user needs 350 USDC on Base (the target network).

```
Target network - Base (8453)
Target asset - USDC
Output amount - 350 USDC
```

### Validation

The user's desired output token amount must be less than or equal to the virtual liquidity balance for the given token. In the current example the user's balance is 400 and the target output amount is 350. Therefore the user's intent is valid.

### Solver Computation

When the user submits the intent the solver calculates the fees required to process the user's intent. The fees includes the fees required to pay for transaction gas fees along with solver fees.&#x20;

The solver computes the user's deficit on the target network and generates the transaction calldata and signatures required by the user to claim/withdraw funds from the VLL contracts to execute their desired transaction.

The solver also includes a reclaim plan, which describes the networks where the solver reimburses itself for the funds lent to the user on the target network, the reclaim plan is described in detail in the section outlining the settlement process given below.

### Claim

The user executes a **claim** function on the VLL paymaster contract for the deficit the user is missing on the target chain. In this example, the user's USDC deficit on Base is 150 USDC. The user borrows the 150 USDC from the paymaster here and the solver later reimburses itself from vaults on the networks where the user does have USDC virtual balance.

### Withdraw

The user executes a **withdraw** function on the VLL vault on Base for the funds the user already has on base, which in this example is 200 USDC.

### Execution

The user's transaction to purchase the NFT is bundled along with the transactions to withdraw and claim USDC from the VLL. These sub-transactions are bundled and executed atomically in the form of a user operation in a single transaction.

### Settlement

Once the user's transaction is executed the solver settlement process begins. In the solver computation step, along with the claim/withdraw signatures, the solver also computes the reclaim plan. In the example above the solver fronts 150 USDC to the user. Lets assume the solver needs 152 USDC to reimburse itself. The additional 2 USDC accounts for the gas fees for the user's transaction and the fees required by the solver. The solver may compute a reclaim plan as given below:

`Ethereum - 100, Arbitrum - 52`<br>

The solver accounts for the user's balances on each individual network, as well as the gas price on each individual network when computing the withdrawal plan. Once the transaction is executed with the signatures from the solver (which encodes the provided reclaim plan), the solver can claim 100 USDC from the vault on ethereum and 52 USDC on the vault from Arbitrum to complete the transaction settlement.


# Liquidity Provisioning

## Overview

LPs can provide liquidity to the VLL for supporting chain abstracted transactions and earn yield generated through VLL transaction fees. Yield earned on top of delegated liquidity (via chain abstracted transaction fees) is split between the LP, solver and protocol. The LP receives at least 30% of the profit, solver receives at least 20% of the profit and the protocol receives at most 50% of the profit. Protocol fee varies to incentivize coordination and desired activity from VLL participants (LPs and solvers).

## edToken

edTokens (Enclave Delegated Tokens) represent shares of ownership in the liquidity accessible to solvers to power user transactions through the VLL. Users may mint or redeem edTokens in exchange for underlying tokens on any supported network of the VLL.

edTokens are not rebase tokens and not 1:1 redeemable for underlying token. Rather they represent shares in the aggregated liquidity pool of the underlying token across all supported networks. The number of underlying tokens redeemable for a single edToken increases as more yield is generated from chain abstracted transactions for the underlying token through the VLL.

edTokens are omnichain tokens and conform to the xERC20 standard and can be transferred as any other ERC20 token would or bridged across networks, to any supported network of the VLL.

## Lifecycle

### Staking

LPs deposit token in exchange for edToken. edToken holders unlike virtual liquidity users do not get the benefits of chain abstracted transactions. Instead edToken holder earn yield on their deposits.

### Unstaking

LPs can choose to redeem the underlying token in exchange for their edTokens. LPs have the option to choose where they would like to receive their underlying tokens. When LPs redeem edTokens their edToken balance is burned.

### Delegating

Existing users that maintain balance of a given token (ex. USDC) in the VLL for chain abstracted transactions may choose to become LPs by delegating their virtual token balance. This can be done by calling a special delegate function to convert a specified amount from their virtual token balance into edTokens. Once users delegate their tokens their virtual balance is reduced porportionately.


# Inventory Management

## Rebalancing Methodology

Currently enclave inventory is composed of USDC across multiple networks. The next set of supported assets include other major stablecoins followed by other blue-chip multi-chain assets. Stablecoin inventory management is determined by reacting to demand based on the different types of protocols / dapps / defi liquidity pools that user's are interfacing with. Enclave VLL is plugged into leading dexes and aggregators to support asset level rebalancing on a given chain based on demand.

Rebalancing funds across networks is done by interfacing with solvers connected to the VLL and integrating directly with bridging protocols.

## Incentive Mechanics

Enclave is building an incentive marketplace that incentivizes solvers and/or LPs to rebalance liquidity to desired networks based on user/dapp/chain demand for liquidity. Chains / protocols / dapps can pledge economic rewards to users for directing user traffic and LPs for adding liquidity to their corresponding chains / protocols / dapps. In the future chains will be able to stake $ENCLAVE to direct a share of VLL liquidity to their chain to support seamless user transaction execution.


# Integrate with Enclave Money


# Embedded Wallet


# Initialize project and setup provider

Let's start by installing the SDK package and initializing the provider.

## 1. Create a react / next repo and install the SDK

Install the npm package in your React or Next JS / TS project.

```
npm i @enclavemoney/enclave-wallet-sdk
```

## 2. Initialise Provider

Import the provider from the installed package. Initialize the API key obtained from the dev portal. Make sure to place the API key in your environment variables. You can select the theme of the embedded wallet based on the theme of your application.&#x20;

```tsx
"use client";

import { WalletProvider } from "@enclavemoney/enclave-wallet-sdk/dist/components/WalletProvider";
import { useTheme } from "@/app/contexts/ThemeContext";
import { NoSSR } from "@/app/components/ui/NoSSR";
import { Dashboard } from "@/app/components/Dashboard";

const sdkKey = process.env.NEXT_PUBLIC_ENCLAVE_SDK_KEY || "";

function WalletWrapper() {
  const { isDarkMode } = useTheme();

  return (
    <WalletProvider sdkKey={sdkKey} theme={isDarkMode ? "dark" : "light"}>
      <NoSSR>
        <Dashboard />
      </NoSSR>
    </WalletProvider>
  );
}

export default function Home() {
  return <WalletWrapper />;
}
```


# Onboarding and Account Access

## 1. Import useWallet hook to access embedded wallet functions

```tsx
import { useWallet } from "@enclavemoney/enclave-wallet-sdk/dist/components/WalletProvider";

export function Page() {
     const {
          isLoggedIn,
          username,
          connect,
          walletSDK,
          disconnect,
     } = useWallet();

     return (
          <div>
               <!-- -->
               {
                    isLoggedIn ? 
                    <div>
                         <button onClick = {() => walletSDK.openWalletModal()}>Welcome {username}</button>
                         <button onClick = {() => disconnect()}>Log Out</button>
                    </div> :
                    <div>
                         <button onClick = {() => connect()}>Log In</button>
                    </div>
               }
          </div>
     )
     
}
```

### 1.a. Login modal after calling connect()

Calling the **connect()** funtion triggers the modal displayed below where user's can continue onboarding

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2FpoiTRYMcXYZcAfTXE2xU%2FScreenshot%202025-06-30%20at%205.33.02%E2%80%AFPM.png?alt=media&amp;token=02c6dcba-183b-4098-9975-8108e4395bb0" alt="" width="375"><figcaption></figcaption></figure>

### 1.b. Wallet modal after calling walletSDK.openWalletModal()

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2FHWEtf9igEkFqCmr5htwq%2FScreenshot%202025-06-30%20at%205.39.57%E2%80%AFPM.png?alt=media&amp;token=96cea0cd-de8f-401d-94f1-39177442b516" alt="" width="375"><figcaption></figcaption></figure>


# Get User Info

Access user details from the useWallet hook

```tsx
import { useWallet } from "@enclavemoney/enclave-wallet-sdk/dist/components/WalletProvider";

export function Page() {
     const {
         isLoggedIn,
         username,
         evmWalletAddress,
         solanaWallkeAddress,
         bitcoinWalletAddress,
         cryptoBalance
     } = useWallet();
}
```

| Variable name        | Data                                                  |
| -------------------- | ----------------------------------------------------- |
| username             | User's username or email id (based on auth mechanism) |
| evmWalletAddress     | EVM smart contract wallet address                     |
| solanaAddress        | Solana wallet address                                 |
| bitcoinWalletAddress | Bitcoin native segwit wallet address                  |
| cryptoBalance        | List of aggregated token balances                     |
| isLoggedIn           | Logged in state of the user (true or false)           |


# Trigger a swap

## 1. Import quote and swap execution functions from useWallet hook&#x20;

```tsx
export function Page() {
     const {
         computeQuote,
         executeSwap,
         executeHeadlessSwap
     } = useWallet();
}
```

## 2. Compute quote for a token swap

```typescript
const quoteResult: any = await calculateQuote({
    fromToken: {
      amount: ethers
        .parseUnits(fromAmount, fromToken.decimals)
        .toString(),
      chainId: fromChain.chainId,
      tokenAddress: fromChain.address,
      
      // Optional
      metadata: {
        tokenName: fromToken.name,
        tokenSymbol: fromToken.symbol,
        decimals: fromToken.decimals,
        logoURI: fromToken.logoURI,
        chainIds: fromToken.chainIds,
      },
    },
    toToken: {
      chainId: toChain.chainId,
      tokenAddress: toChain.address,
      
      // Optional
      metadata: {
        tokenName: toToken.name,
        tokenSymbol: toToken.symbol,
        decimals: toToken.decimals,
        logoURI: toToken.logoURI,
        chainIds: toToken.chainIds,
      },
    },
});
```

## 3. Execute the swap

### 3.a. Normal swap

Trigger the swap modal built into the embedded wallet

```typescript
swap({
  fromToken: {
    tokenAddress: fromTokenAddress,
    chainId: fromTokenChainId,
    
    // Optional
    metadata: {
      tokenName: fromTokenName,
      tokenSymbol: fromTokenSymbol,
      decimals: fromTokenDecimals,
      logoURI: fromTokenLogoURI
    },
  },
  toToken: {
    tokenAddress: toTokenAddress,
    chainId: toTokenChainId,
  },
});
```

Calling **swap()** triggers the swap modal where user's can execute their trade

<figure><img src="https://2429876521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGaftPmsUdt8hxUf6uzhp%2Fuploads%2F0RaPpWY1QViI9FvSTFX9%2FScreenshot%202025-06-30%20at%206.18.49%E2%80%AFPM.png?alt=media&amp;token=08ba390e-bc20-4596-8c93-08022eb26bdc" alt="" width="375"><figcaption></figcaption></figure>

### 3.b. Headless swap

A headless swap is a swap that's executed directly from the context of the parent application without triggering the embedded wallet swap popup. This alternate method can be used when the app wants complete end-to-end control over the swap UX without relying on the embedded wallet's swap interface.

#### Quote Selection

For headless swaps, since user's don't go through the embedded wallet interface, the quote response provides the app developer the option of choosing between the quote with best price execution and the quote that executes the swap the fastest. The developer can pass this decision on to the user or choose on behalf of the user.

Quote results have 2 types: **quote.bestQuote** which returns the highest amount out for the given input token amount and swap pair and **quote.fastestQuote** which executes the swap in the lowest possible time. When **quote.duplicate** is **true** then both the quotes (the one with the best rate and one with the fastest execution time) are from the same provider and there is no choice to be made. If not, the app developer can choose on behalf of the user or&#x20;

```typescript
const handleExecuteSwap = async () => {
    if (!isLoggedIn || !quote) {
      connect();
      return;
    }

    try {
      setIsLoading(true);
      const fromChain = fromToken.chainIds[0];
      const toChain = toToken.chainIds[0];

      // Get the provider from the selected quote
      
      // App developers can write their own logic to select between 
      // quoteResult.bestQuote and quoteResult.fastestQuote from the quoteResult object
      // in the code snippet above, where we call calculateQuote
      const selectedQuote = getSelectedQuote();
      const provider =
        selectedQuote && "provider" in selectedQuote
          ? (selectedQuote.provider as ProtocolProvider)
          : isMultipleQuotesResponse(quote)
          ? selectedQuoteType === "best"
            ? quote.bestQuote.provider
            : quote.fastestQuote.provider
          : undefined;

      const result = await executeSwap({
        fromToken: {
          amount: ethers.parseUnits(fromAmount, fromToken.decimals).toString(),
          chainId: fromChain.chainId,
          tokenAddress: fromChain.address,
          
          // Optional
          metadata: {
            tokenName: fromToken.name,
            tokenSymbol: fromToken.symbol,
            decimals: fromToken.decimals,
            logoURI: fromToken.logoURI,
            
            // For multichain swaps, the user can select which chains to spend funds from
            // For example a user with 100 USDC on Arbitrum Base and Solana each could
            // choose to spend 50 USDC from Base and 50 from Solana
            // chainIds: [
            //  {chainId: Networks.SOLANA, amount: 50000000, address: solanaTokenAddress},
            //  {chainId: Networks.BASE, amount: 50000000, address: baseTokenAddress},
            // ]
            // If left blank then Enclave's best path algorithm automatically selects the
            // most optimal distribution to spend based on available liquidity and gas fees
            chainIds: fromToken.chainIds,
          },
        },
        toToken: {
          chainId: toChain.chainId,
          tokenAddress: toChain.address,
          
          // Optional
          metadata: {
            tokenName: toToken.name,
            tokenSymbol: toToken.symbol,
            decimals: toToken.decimals,
            logoURI: toToken.logoURI,
            
            // For multichain swaps, the user can select which chains to receive funds on
            // For example a user could choose to receive USDT as the output token on 
            // Binance smart chain.
            // chainIds: [
            //  {chainId: Networks.BSC, address: bscTokenAddress},
            // ]
            // If left blank then Enclave's best path algorithm automatically selects the
            // most optimal output chain based on available liquidity and gas fees
            chainIds: toToken.chainIds,
          },
        },
        ...(provider && { provider: provider as ProtocolProvider }),
      });

      console.log("Swap executed:", result);
    } catch (error) {
      console.error("Swap execution failed:", error);
    } finally {
      setIsLoading(false);
    }
  };
```


# Trigger a token transfer


# SDK Reference

## Typescript Javascript SDK

{% embed url="<https://npmjs.com/package/enclavemoney>" %}

### Demo Application

{% embed url="<https://github.com/Enclave-Money/demopay>" %}

### Code Walkthrough Video

{% embed url="<https://vimeo.com/1043121854>" %}

## Integration Guides

{% content-ref url="/pages/x3Hr0iz6zEb0djdxmntp" %}
[Integrate with Privy](/integrate-with-enclave-money/sdk-reference/integrate-with-privy)
{% endcontent-ref %}

{% content-ref url="/pages/tTW2xiK9VJFIxkXrbkAv" %}
[Integrate with Turnkey](/integrate-with-enclave-money/sdk-reference/integrate-with-turnkey)
{% endcontent-ref %}


# Integrate with Privy

## Demo Repository

{% embed url="<https://github.com/Enclave-Money/enclave-privy-demo>" %}

## Code Walkthrough Video

{% embed url="<https://vimeo.com/1044448020>" %}


# Integrate with Turnkey

The steps given below contain instructions on how to integrate Enclave's SDK with an application that uses Turnkey's React SDK

## Demo Repository

{% embed url="<https://github.com/Enclave-Money/enclave-turnkey-demo>" %}

## Step 1: Install Enclave Money

```
npm install enclavemoney
```

## Step 2: Initialize Enclave Client

```typescript
import { Enclave, SignMode } from 'enclavemoney';
const API_KEY = 'your-api-key-here';
const enclave = new Enclave(API_KEY);
```

## Step 3: Create Account with Turnkey as Signing Key

In the snippet given below we:

* Import 3rd party dependencies
* &#x20;Retrieve the active Turnkey signing key address
* Create an Enclave account on all supported networks using the Turnkey signing key

```typescript
import { useState, useEffect } from "react";
import { useTurnkey } from "@turnkey/sdk-react";
import { formatUnits, parseUnits, isAddress, ethers, getBytes } from 'ethers';

....

const { turnkey, getActiveClient } = useTurnkey();

const client = await getActiveClient();

// The user's sub-organization id
const organizationId = user?.organization.organizationId;

// Get the user's wallets
const wallets = await client?.getWallets({
  organizationId,
});

// Get the first wallet of the user
const walletId = wallets?.wallets[0].walletId ?? "";

// Use the `walletId` to get the accounts associated with the wallet
const accounts = await client?.getWalletAccounts({
  organizationId,
  walletId,
});

const signingKey = accounts?.accounts[0].address;

const account = await enclave.createSmartAccount(signingKey);
console.log('Smart Account created:', account.wallet.scw_address);

```

The user can transfer USDC to the account address returned from the createSmartAccount response and start transacting on any supported chain with their USDC deposits.

## Step 3: Build User Operation

In the example below we build a user operation to transfer USDC. This requires the user to have an account (created in **Step 2**) and the user must transfer USDC to their account. The user can deposit USDC on any supported chain and spend their funds on any chain.

<pre class="language-typescript"><code class="lang-typescript">// Define the transaction details
// Define the USDC contract address on Optimism
const usdcContractAddress = '&#x3C;Insert USDC Contract Address for Chain ID>'; 

// Define the recipient address and amount to transfer
const recipientAddress = '0x...'; // Replace with the recipient's address
const amount = ethers.parseUnits('1', 6); // Amount of USDC to transfer (1 USDC)

// Create the call data for the ERC20 transfer
const erc20Interface = new ethers.Interface([
    'function transfer(address to, uint256 amount)'
]);
const encodedData = erc20Interface.encodeFunctionData('transfer', [recipientAddress, amount]);

const transactionDetails = [{
    encodedData, 
    targetContractAddress: usdcContractAddress,
    value: 0 // Assuming no ETH is being transferred, only USDC
}];

// Define the order data - Describes how much the user wants to spend from their chain-abstracted balances
// Understanding order type
// AMOUNT_OUT: User needs 100 USDC on the target network. The user will be charged 100 + fees.
// AMOUNT_IN : User is charged 100 USDC and receives (100 - fees) on target network 
<strong>const orderData = {
</strong>    amount: amount.toString(), // Amount of USDC required for the transfer 
    type: 'AMOUNT_OUT'
};

// Build the transaction
const builtTxn = await enclave.buildTransaction(
    transactionDetails,
    chainId, // chainId of the network you want to execute the transaction on
    account.wallet.scw_address, // User's smart account address
    orderData,
    undefined, // Pass custom ERC4337 paymaster signature if required
    SignMode.ECDSA // ECDSA Signature Mode (for secp256k1)
);
</code></pre>

## Step 4: Sign User Operation

In the snippet below we create a Turnkey ethers signer and sign the user operation hash (buildTxn.messageToSign) retriveed in **Step 3**.

```typescript
const turnkeySigner = new TurnkeySigner({
    client: client,
    organizationId: user.organization.organizationId,
    signWith: accounts.accounts[0].address,
}) 
console.log("UserOpHash To Sign: ", builtTxn.messageToSign);

const msgBytes = getBytes(builtTxn.messageToSign);
const signature = await turnkeySigner.signMessage(msgBytes);
```

## Step 5: Submit User Operation

In the code snippet given below we use the enclave SDK to submit the signed user operation using builtTxn from **Step 3** and the signature from **Step 4**

```typescript
const txnResult = await enclave.submitTransaction(
  signature,
  builtTxn.userOp,
  chainId, // chainId of the network you want to execute the transaction on
  enclaveAddress,
  SignMode.ECDSA
);
```

## Conclusion

Congratulations! You have now added chain abstraction capabilities to your application using Turnkey as the signing key. This effectively allows your users to spend their unified USDC balance across chains for executing any on-chain action using their preferred authentication, authorization and signing methods provided by Turnkey (ex. Email, Google, Passkey, etc).


# API Reference


# Health

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/api/health" method="get" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}


# User

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

{% openapi src="<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>" path="/user" method="get" %}
<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>
{% endopenapi %}

{% openapi src="<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>" path="/api/user/search" method="get" %}
<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>
{% endopenapi %}

{% openapi src="<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>" path="/api/user/check-username" method="get" %}
<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>
{% endopenapi %}


# Smart Balance

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/smartbalance/getbalance" method="get" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/smartbalance/getquote" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/smartbalance/computesolution" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}


# Smart Account

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/smart-account/create" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/smart-account/transaction/build" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/smart-account/transaction/submit" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/smart-account/transaction/gas-fees" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}


# Passkey Account

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/webauthn/register/generate-options" method="get" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/webauthn/register/verify" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>" path="/webauthn/authenticate/generate-options" method="get" %}
<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>
{% endopenapi %}

{% openapi src="<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>" path="/webauthn/authenticate/verify" method="post" %}
<https://enclave-b2b-api-wgltufiroq-el.a.run.app/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/webauthn/transaction/generate-options" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/v3/webauthn/transaction/verify" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}


# Delegated Action

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

{% openapi src="<https://hyperapp.in/api-docs.json>" path="/smart-account/delegate-action" method="post" %}
<https://hyperapp.in/api-docs.json>
{% endopenapi %}


# Unified Deposit Address

Endpoints to create and manage unified deposit addresses

**Base URL**

```
https://api.enclave.money
```

**Authorization**

```
Headers: {
    ...
    Authorization: <YOUR_API_KEY>
}
```

## Getting Started

Get started by creating a UDA for a user using the API endpoint below. This endpoint can be integrated as part of your onboarding flow.

## Create a new unified deposit address for a user

> Create a new unified deposit address for a user within an organization. Requires authentication.

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/create":{"post":{"summary":"Create a new unified deposit address for a user","description":"Create a new unified deposit address for a user within an organization. Requires authentication.","tags":["Unified Deposit Address"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userId","destinationChainId","destinationAddress","destinationTokenAddress"],"properties":{"userId":{"type":"string","description":"Unique user identifier"},"destinationChainId":{"type":"integer","description":"Destination chain ID (EVM chainId)"},"destinationAddress":{"type":"string","description":"Destination wallet address (EVM address)"},"destinationTokenAddress":{"type":"string","description":"Destination token contract address (EVM address)"}}}}}},"responses":{"201":{"description":"Unified deposit address created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"Unified deposit address object"}}}}}},"400":{"description":"Missing or invalid required fields","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Conflict - user or enclaveId already has an active unified deposit address","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

In case you want to create multiple UDAs for your existing users at once, you can use the batch creation endpoint below.

## Create multiple unified deposit addresses in batch

> Create multiple unified deposit addresses for users within an organization in a single request. Requires authentication. Batch size is limited to 50.

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/create/batch":{"post":{"summary":"Create multiple unified deposit addresses in batch","description":"Create multiple unified deposit addresses for users within an organization in a single request. Requires authentication. Batch size is limited to 50.","tags":["Unified Deposit Address"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requests"],"properties":{"requests":{"type":"array","items":{"type":"object","required":["userId","destinationChainId","destinationAddress","destinationTokenAddress"],"properties":{"userId":{"type":"string","description":"Unique user identifier"},"destinationChainId":{"type":"integer","description":"Destination chain ID"},"destinationAddress":{"type":"string","description":"Destination wallet address"},"destinationTokenAddress":{"type":"string","description":"Destination token contract address"}}}}}}}}},"responses":{"201":{"description":"Batch unified deposit addresses created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"Unified deposit address object"},"error":{"type":"string"}}}}}}}}},"400":{"description":"Invalid request or batch size exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Fetch unified deposit address details for a specific user

> Retrieve the unified deposit address for a user within an organization. Requires authentication.

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/user/{userId}":{"get":{"summary":"Fetch unified deposit address details for a specific user","description":"Retrieve the unified deposit address for a user within an organization. Requires authentication.","tags":["Unified Deposit Address"],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Unique user identifier"}],"responses":{"200":{"description":"Unified deposit address found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"Unified deposit address object"}}}}}},"400":{"description":"Missing required parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Unified deposit address not found for this user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Update destination details for a unified deposit address

> Update the destination chain, address, and token for a user's unified deposit address. Requires authentication.

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/user/{userId}/destination":{"put":{"summary":"Update destination details for a unified deposit address","description":"Update the destination chain, address, and token for a user's unified deposit address. Requires authentication.","tags":["Unified Deposit Address"],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Unique user identifier"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["destinationChainId","destinationAddress","destinationTokenAddress"],"properties":{"destinationChainId":{"type":"integer","description":"Destination chain ID (EVM chainId)"},"destinationAddress":{"type":"string","description":"Destination wallet address (EVM address)"},"destinationTokenAddress":{"type":"string","description":"Destination token contract address (EVM address)"}}}}}},"responses":{"200":{"description":"Destination details updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","description":"Updated unified deposit address object"}}}}}},"400":{"description":"Missing or invalid required fields","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Unified deposit address not found for this user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Fetch all unified deposit addresses for an organization

> Retrieve all unified deposit addresses for the authenticated organization. Supports optional status filter and pagination. If \`all=true\` is provided, returns all addresses for the organization (ignores pagination).

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/organization":{"get":{"summary":"Fetch all unified deposit addresses for an organization","description":"Retrieve all unified deposit addresses for the authenticated organization. Supports optional status filter and pagination. If `all=true` is provided, returns all addresses for the organization (ignores pagination).","tags":["Unified Deposit Address"],"parameters":[{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["ACTIVE","INACTIVE","PENDING","DISABLED"]},"description":"Filter by deposit address status"},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","default":50,"minimum":1,"maximum":100},"description":"Number of results to return (pagination)"},{"in":"query","name":"offset","required":false,"schema":{"type":"integer","default":0,"minimum":0},"description":"Offset for pagination"},{"in":"query","name":"all","required":false,"schema":{"type":"boolean"},"description":"If true, fetch all addresses for the organization (ignores pagination)"}],"responses":{"200":{"description":"List of unified deposit addresses","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","description":"Unified deposit address object"}},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"count":{"type":"integer"}}}}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Fetch unified deposit address details by internal enclaveId

> Retrieve the unified deposit address by its internal enclaveId (UUID v4). Requires authentication. Intended for internal services.

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/enclave/{enclaveId}":{"get":{"summary":"Fetch unified deposit address details by internal enclaveId","description":"Retrieve the unified deposit address by its internal enclaveId (UUID v4). Requires authentication. Intended for internal services.","tags":["Unified Deposit Address"],"parameters":[{"in":"path","name":"enclaveId","required":true,"schema":{"type":"string","format":"uuid"},"description":"Internal enclaveId (UUID v4)"}],"responses":{"200":{"description":"Unified deposit address found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"Unified deposit address object"}}}}}},"400":{"description":"Missing or invalid enclaveId","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Unified deposit address not found for this enclaveId","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Query the status of a teleport request

> Get the status of a teleport request by source chain ID and source transaction hash. Requires authentication.

```json
{"openapi":"3.0.0","info":{"title":"Enclave Wallet API","version":"1.0.0"},"security":[{"ApiKeyAuth":[]}],"paths":{"/unified-deposit-address/teleport/status":{"get":{"summary":"Query the status of a teleport request","description":"Get the status of a teleport request by source chain ID and source transaction hash. Requires authentication.","tags":["Unified Deposit Address"],"parameters":[{"in":"query","name":"sourceChainId","required":true,"schema":{"type":"integer"},"description":"Source chain ID of the depost transaction"},{"in":"query","name":"inboundTransactionHash","required":true,"schema":{"type":"string"},"description":"Transaction hash of the deposit transaction"}],"responses":{"200":{"description":"Teleport request status returned successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"multiTransactionId":{"type":"string"},"overallStatus":{"type":"string","enum":["PENDING","COMPLETED","FAILED","PARTIAL"]},"transactionType":{"type":"string"},"sourceChains":{"type":"array","items":{"type":"integer"}},"destinationChains":{"type":"array","items":{"type":"integer"}},"inputTransactions":{"type":"object","description":"Map of chainId to transaction details"},"outputTransactions":{"type":"object","description":"Map of chainId to array of transaction details"},"metadata":{"type":"object","description":"Transaction metadata including token details, amounts, and fees"},"estimatedTime":{"type":"number"},"createdTimestamp":{"type":"number"},"lastUpdatedTimestamp":{"type":"number"}}}}}},"400":{"description":"Missing required parameters","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"}}}}}},"404":{"description":"No teleport request found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"}}}}}}}}}}}
```


# Applications

What you can build using Enclave's API

The following applications can be built by integrating Enclave's API

* Mirrortables (<https://balajis.com/p/mirrortable>)
* Cross chain borrow lend: Stake collateral on chain 1 and borrow asset on chain 2
* Cross chain NFT marketplaces
* Cross chain prime brokerage - Multi utilization of collateral across chains and protocols for maximum capital efficiency
* AI Execution Engine - Virtual environment for rule based transaction orchestration and execution, perfect for autonomous transaction execution use cases / users (ex. AI agents)


# Business Model

Enclave provides businesses access to APIs and works on a usage based model.\
Clients building applications and integrating Enclave APIs pay for usage based on the following:

* Cost per user per month
* Cost per transaction
* Cost per enabled network


# Audits

Audits coming soon.


# Disclaimer

Enclave Money ("Enclave") is a technology infrastructure provider that develops and maintains blockchain interoperability APIs. We facilitate communication between different blockchain networks through our technical solutions.

### What We Are

* A technology company providing blockchain interoperability infrastructure
* An API service provider enabling cross-chain communication
* A developer platform offering tools for blockchain integration

### What We Are Not

* We are not a token issuer or creator
* We do not issue, manage, or control any cryptocurrency or digital assets
* We are not a cryptocurrency exchange or financial institution
* We do not provide financial advice or investment recommendations

### Service Clarity

Our APIs and infrastructure services are purely technical in nature. Any reference to blockchain networks or protocols in our services is strictly for technical implementation purposes.

### Business Model

Our business model is based on providing technical infrastructure and API services. We charge for API usage and technical implementation.&#x20;

### Important Notice

The presence of "money" in our domain name (enclave.money) refers to our focus on financial technology infrastructure and does not indicate any involvement in direct financial services, cryptocurrency issuance, or asset management.

### Limitation of Liability

Enclave Money makes no guarantees regarding the performance of blockchain networks or protocols that our APIs interact with. Users implement our APIs at their own risk and should conduct their own due diligence regarding the technical and regulatory requirements of their specific use cases.


# Risk Disclosure

Enclave is dedicated to providing a secure and efficient API for transacting across chains. However, as with any crypto application, there are inherent risks associated with using Enclave. It is important for chains, dapps and users to understand these risks before participating.&#x20;

## Network Congestion Risk

High transaction volumes on blockchain networks can lead to congestion, resulting in delayed transactions and higher fees. This can affect the efficiency and cost-effectiveness of Enclave's operations, including deposits, withdrawals, and rebalancing activities.

## 51% Attack

A 51% attack occurs when a single entity or group gains control of more than 50% of the blockchain network's hashing power or stake. This control can be used to manipulate the blockchain, including reversing transactions, double-spending, and preventing new transactions from being confirmed.

* **Impact on Enclave**: If a 51% attack occurs on any of the networks supported by Enclave Money, it could lead to disruptions in operations, loss of funds, or incorrect updates to the state of the fund pool reserves and user balances.

## Chain Rollback

A chain rollback is an event where a blockchain network is reverted to a previous state, effectively undoing transactions that occurred after the rollback point. This can happen due to software bugs, consensus issues, or malicious attacks.

## Mitigation Measures

Enclave Money takes several measures to mitigate these risks, including:

* **Security Audits**: Regular and thorough security audits of Enclave's smart contracts and protocols.
* **Monitoring**: Continuous monitoring of network conditions and security developments to respond quickly to potential threats.
* **Community and Governance**: Engaging with the community and participating in governance processes of integrated protocols to stay informed and influence security practices.


