> For the complete documentation index, see [llms.txt](https://docs.epochprotocol.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.epochprotocol.xyz/integration-guides/sdk-integration-guide.md).

# SDK Integration Guide

Add Epoch cross-chain intent flows to any JavaScript/TypeScript project using `@epoch-protocol/epoch-intents-sdk`. Reference implementation: [compact-demo-epoch](/integration-examples.md#compact-demo-epoch).

> This guide is adapted from [skills.md](/integration-guides/skills-md.md).

***

## Integration Checklist

```
- [ ] Install @epoch-protocol/epoch-intents-sdk, viem (peer dep)
- [ ] Set apiBaseUrl env var (testnet: https://testnet-dev.epochprotocol.xyz)
- [ ] Configure wallet client (viem or wagmi) on a supported chain
- [ ] Fetch allocator address via sdk.getHealthCheck() (do not hard-code)
- [ ] Implement: getTaskData → getIntentQuote → solveIntent → getIntentStatus
- [ ] Use testnetGraph/mainnetGraph for token/chain discovery
- [ ] (Optional, testnet) Gasless Compact deposits: `convertToSmartAccount` → `solveIntent({ gasless: true, allowGaslessSmartAccount: true })` — see [Gasless Deposits](gasless-deposits.md)
```

***

## Install

```bash
npm install @epoch-protocol/epoch-intents-sdk viem
```

**Requirements:** Node.js 18+, TypeScript 5+, viem 2.x

***

## Environment

```bash
# .env
VITE_API_BASE_URL=https://testnet-dev.epochprotocol.xyz   # Vite
NEXT_PUBLIC_EPOCH_API_BASE=https://testnet-dev.epochprotocol.xyz  # Next.js
EPOCH_API_BASE=https://testnet-dev.epochprotocol.xyz        # Node.js
```

Always read the allocator address at runtime via `sdk.getHealthCheck()` — do not rely on stale SDK constants.

***

## APIs Quick Reference

<table><thead><tr><th width="270.38671875">Item</th><th>Value</th></tr></thead><tbody><tr><td>SDK <code>apiBaseUrl</code> (testnet)</td><td><code>https://testnet-dev.epochprotocol.xyz</code></td></tr><tr><td>SDK <code>apiBaseUrl</code> (mainnet)</td><td><code>https://api.epochprotocol.xyz</code></td></tr></tbody></table>

Full chain and token tables: [Supported Chains & Tokens](/supported-chains-and-tokens.md).

***

## Core Intent Flow

```
→ getHealthCheck()
→ getTaskData({ taskType, intentData })
→ getIntentQuote({ sponsorAddress, taskTypeString, intentData, routingAndLiquidityOptions? })
→ solveIntent({ ...params, quoteResult, routingAndLiquidityOptions?, onExecutionStatus })
→ getIntentStatus(userAddress, nonce)
```

The SDK handles ERC-20 approval and Compact deposits automatically inside `solveIntent`.

***

## Vanilla TypeScript (Node / any JS)

```typescript
import { EpochIntentSDK, TaskType } from "@epoch-protocol/epoch-intents-sdk";
import { createWalletClient, http, parseUnits } from "viem";
import { baseSepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
  chain: baseSepolia,
  transport: http(),
  account,
});

const sdk = new EpochIntentSDK({
  apiBaseUrl: process.env.EPOCH_API_BASE!,
  walletClient,
});

// 1. Health check
const health = await sdk.getHealthCheck();
console.log("Allocator:", health.allocatorAddress);

// 2. Build task data
const { taskTypeString, intentData } = await sdk.getTaskData({
  taskType: TaskType.GetTokenOut,
  intentData: {
    isNative: false,
    depositTokenAddress: "0x2BB4FfD7E2c6D432b697554Efd77fA13bdbefd69", // USDC
    tokenInAmount: parseUnits("100", 18).toString(),
    outputTokenAddress: "0x7946dd86eE310D0aC16804A37787289Fa5b88A8A", // WETH
    minTokenOut: parseUnits("0.05", 18).toString(),
    destinationChainId: "11155111", // Sepolia
    protocolHashIdentifier:
      "0x0000000000000000000000000000000000000000000000000000000000000000",
    recipient: account.address,
  },
  extraDataTypestring: "uint256 somethingKey",
  extraData: { somethingKey: "123" },
});

// 3. Quote
const quoteResult = await sdk.getIntentQuote({
  sponsorAddress: account.address,
  taskTypeString,
  intentData,
  isNative: false,
});

// 4. Solve (deposit + register + submit intent)
const result = await sdk.solveIntent({
  isNative: false,
  sponsorAddress: account.address,
  taskTypeString,
  intentData,
  quoteResult,
  onExecutionStatus: (s) => console.log(s.phase, s.transactionHash),
});

const nonce = result.allocationResponse?.nonce;

// 5. Poll status
if (nonce) {
  const status = await sdk.getIntentStatus(account.address, nonce);
  console.log(status);
}
```

See [epoch-integration-demo](/integration-examples.md#epoch-integration-demo) for a runnable Node.js script.

### Routing & liquidity options (optional)

Use `routingAndLiquidityOptions` when you want to control **how** the swap is filled — single-transaction filler liquidity (one user signature, seamless end-to-end execution including protocol interactions) vs multi-transaction external routing vs best-of-all.

```typescript
import type { RoutingAndLiquidityOptions } from "@epoch-protocol/epoch-intents-sdk";

const routingAndLiquidityOptions: RoutingAndLiquidityOptions = {
  preset: "filler-single-transaction",
};

const quoteResult = await sdk.getIntentQuote({
  sponsorAddress: account.address,
  taskTypeString,
  intentData,
  routingAndLiquidityOptions,
});

await sdk.solveIntent({
  isNative: false,
  sponsorAddress: account.address,
  taskTypeString,
  intentData,
  quoteResult,
  routingAndLiquidityOptions, // same as quote
});
```

Presets: `any` (default), `filler-single-transaction` (one transaction, seamless end-to-end execution for the user — protocol interactions handled by the filler), `external-multi-transactions`, `custom` (with `solvers: [\`0x…\`]\`). See [SDK Reference](/integration-guides/sdk-reference.md#getintentquoteparams).

***

## React + wagmi Pattern (from compact-demo-epoch)

### 1. Wagmi chains

Configure viem testnet/mainnet chains in wagmi config (`compact-demo-epoch/src/config/wagmi.ts`):

```typescript
import {
  sepolia,
  baseSepolia,
  optimismSepolia,
  base,
  optimism,
  polygon,
  arbitrum,
} from "viem/chains";

export const chains = [
  sepolia,
  baseSepolia,
  optimismSepolia,
  polygon,
  arbitrum,
  base,
  optimism,
] as const;
```

### 2. Token/chain discovery from SDK graphs

```typescript
import { mainnetGraph, testnetGraph } from "@epoch-protocol/epoch-intents-sdk";

// compact-demo-epoch/src/config/web3.ts pattern:
// - Pick graph by chainId (mainnet vs testnet)
// - getTokensForChain(chainId) → { symbol, address, decimals }[]
// - getChainsFromGraph(chainId) → destination chain options
```

### 3. Instantiate SDK per action

```typescript
import { useWalletClient } from "wagmi";
import { EpochIntentSDK, TaskType } from "@epoch-protocol/epoch-intents-sdk";

const { data: walletClient } = useWalletClient();

const sdk = new EpochIntentSDK({
  apiBaseUrl: import.meta.env.VITE_API_BASE_URL,
  walletClient: walletClient as any,
});
```

### 4. Swap submit (compact-demo-epoch/src/pages/BalancePage.tsx)

1. `getTaskData` with `TaskType.GetTokenOut`
2. `getIntentQuote` — store `quoteResult`
3. `solveIntent` with `quoteResult` and `onExecutionStatus` callback
4. Save `data.allocationResponse.nonce` for status polling
5. `getIntentStatus(address, nonce)`

### 5. Compact balances & withdrawals

```typescript
// compact-demo-epoch/src/components/UserBalancesList.tsx
const results = await sdk.getDepositedBalances(address, tokenInputs);

// compact-demo-epoch/src/components/WalletWithdrawDialog.tsx
await sdk.initateDepositWithdrawal(depositId);
await sdk.withdrawToken(depositId, recipient, amountWei);
await sdk.disableForcedWithdrawal(depositId);
```

### 6. Health / allocator address

```typescript
const health = await sdk.getHealthCheck();
const { allocatorAddress, chainConfig } = health;
```

### 7. Gasless mode (testnet, optional)

**Local private-key wallets:** users sign only — the allocator relays Compact deposits via epoch-sio (gasless). **Injected wallets:** gasless relay is not available; the SDK may batch calls via `wallet_sendCalls` when the wallet is already a smart account, but the user pays gas:

```typescript
// One-time explicit smart-account conversion (local private-key wallet)
await sdk.convertToSmartAccount({ chainId: 84532 });

const result = await sdk.solveIntent({
  // ...standard solve params
  quoteResult,
  gasless: true,
  allowGaslessSmartAccount: true, // local wallet: strict relay, no auto-convert
});

if (result.gaslessUsed) {
  console.log("Gasless path used — user did not pay on-chain gas");
}
```

**Injected wallets:** SDK does not prompt smart-wallet upgrade. Gasless relay is for local signers; browser wallets use wallet-paid execution with optional batching when already a smart wallet.

Probe before showing UI:

```typescript
const status = await sdk.getWalletGaslessStatus(chainId);
```

**Local integration test:** `cd smallocator/sdk && pnpm example:local-wallet` — see [Gasless Deposits](/integration-guides/gasless-deposits.md#local-integration-test-end-to-end).

Full guide: [Gasless Deposits](/integration-guides/gasless-deposits.md). Architecture, batching, and SIO relay: [Transaction Batching & EIP-7702](/integration-guides/transaction-batching-and-eip7702.md).

***

## Task Types

| Task            | Enum                           | Use case                         |
| --------------- | ------------------------------ | -------------------------------- |
| Swap / bridge   | `TaskType.GetTokenOut`         | Cross-chain token output         |
| Protocol action | `TaskType.ProtocolInteraction` | NFT buy, raffle, lending, etc.   |
| Deposit only    | `TaskType.Deposit`             | Lock funds without a swap intent |

***

## Key SDK Exports

```typescript
import {
  EpochIntentSDK,
  TaskType,
  CollateralType,
  COMPACT_ADDRESS,
  SUPPORTED_CHAINS,
  mainnetGraph,
  testnetGraph,
  createLockTag,
  getTokenId,
  getAllocatorId,
} from "@epoch-protocol/epoch-intents-sdk";
```

***

## compact-demo-epoch File Map

| File                                      | Purpose                             |
| ----------------------------------------- | ----------------------------------- |
| `src/config/wagmi.ts`                     | Supported chains + RainbowKit       |
| `src/config/web3.ts`                      | Token/chain discovery from graphs   |
| `src/config/api.ts`                       | `VITE_API_BASE_URL` helper          |
| `src/hooks/useAllocatorAPI.ts`            | Health check, allocator address     |
| `src/hooks/useEffectiveWallet.ts`         | Browser wallet + local signer       |
| `src/hooks/useGaslessWallet.ts`           | Gasless probe + smart-account setup |
| `src/components/GaslessEnableButton.tsx`  | Gasless toggle UI                   |
| `src/components/WalletConnect.tsx`        | RainbowKit + local signer form      |
| `src/pages/BalancePage.tsx`               | Quote → solve (`gasless`) → status  |
| `src/components/UserBalancesList.tsx`     | `getDepositedBalances`              |
| `src/components/WalletWithdrawDialog.tsx` | Forced withdrawal flow              |

***

## Common Mistakes

* Hard-coding allocator address instead of calling `getHealthCheck()`
* Submitting `solveIntent` without a prior `getIntentQuote`
* Wrong `destinationChainId` type — pass as **string** (e.g. `"84532"`)
* Using mainnet `apiBaseUrl` on testnet chains (or vice versa)
* Forgetting viem `walletClient` must have `.chain` and `.account` set

***

## Next steps

* [SDK Reference](/integration-guides/sdk-reference.md) — full method documentation
* [Gasless Deposits](/integration-guides/gasless-deposits.md) — EIP-7702 testnet relay
* [Transaction Batching & EIP-7702](/integration-guides/transaction-batching-and-eip7702.md) — EIP-5792 batching, SIO architecture, test scripts
* [Error Handling](/integration-guides/error-handling.md)
* [Integration Examples](/integration-examples.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.epochprotocol.xyz/integration-guides/sdk-integration-guide.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
