Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/e2e-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
version: 10

- name: Setup Node.js
uses: actions/setup-node@v4
Expand All @@ -26,7 +26,7 @@ jobs:
cache: 'pnpm'

- name: Install dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Build all packages
run: pnpm build
Expand Down
109 changes: 88 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ Learn more: [x402.org](https://x402.org)

## Prerequisites

Before using ClawSwap, you need:

- **Node.js** >= 18.0.0
- **Node.js** >= 18.0.0 (server-side) or **modern browser** (client-side — Chrome, Firefox, Safari, Edge)
- **Package Manager**: npm, pnpm, or yarn
- **For Solana → Base swaps**: Solana wallet with private key (base58-encoded), 0.5 USDC (swap fee), ~0.01 SOL (gas)
- **For Base → Solana swaps**: EVM wallet with private key (0x-prefixed hex), USDC on Base, small amount of ETH on Base (~$0.001 gas)
- **For Solana → Base swaps**: Solana wallet with 0.5 USDC (swap fee) + ~0.01 SOL (gas)
- **For Base → Solana swaps**: EVM wallet with USDC on Base + small amount of ETH (~$0.001 gas)

> The SDK has zero Node.js dependencies and works in any environment with the Fetch API.

<details>
<summary>Getting a Solana Wallet</summary>
Expand Down Expand Up @@ -125,13 +125,13 @@ const client = new ClawSwapClient({ fetch: fetchWithPayment });

// 2. Execute swap
const swap = await client.executeSwap({
sourceChainId: 'solana',
sourceTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
destinationChainId: 'base',
destinationTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
sourceChain: 'solana',
sourceToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
destinationChain: 'base',
destinationToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
amount: '1000000',
senderAddress: 'your-solana-address',
recipientAddress: '0x-your-base-address',
userWallet: 'your-solana-address',
recipient: '0x-your-base-address',
});

// 3. Sign and submit to Solana
Expand All @@ -148,12 +148,12 @@ const signature = await connection.sendRawTransaction(tx.serialize(), {
await connection.confirmTransaction(signature, 'confirmed');

// 4. Wait for settlement
const result = await client.waitForSettlement(swap.orderId, {
const result = await client.waitForSettlement(swap.requestId, {
timeout: 300_000,
interval: 3000,
onStatusUpdate: (status) => console.log(`Status: ${status.status}`),
});
console.log(`Swap completed: ${result.destinationAmount} tokens delivered`);
console.log(`Swap completed: ${result.outputAmount} tokens delivered`);
```

### Base → Solana (free, no x402)
Expand All @@ -170,13 +170,13 @@ const client = new ClawSwapClient();

// 2. Execute swap
const swap = await client.executeSwap({
sourceChainId: 'base',
sourceTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
destinationChainId: 'solana',
destinationTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
sourceChain: 'base',
sourceToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
destinationChain: 'solana',
destinationToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
amount: '1000000',
senderAddress: '0x-your-base-address',
recipientAddress: 'your-solana-address',
userWallet: '0x-your-base-address',
recipient: 'your-solana-address',
});

// 3. Sign and submit to Base (execute transactions in order)
Expand All @@ -197,14 +197,81 @@ if (isEvmSource(swap)) {
}

// 4. Wait for settlement
const result = await client.waitForSettlement(swap.orderId, {
const result = await client.waitForSettlement(swap.requestId, {
timeout: 300_000,
interval: 3000,
onStatusUpdate: (status) => console.log(`Status: ${status.status}`),
});
console.log(`Swap completed: ${result.destinationAmount} tokens delivered`);
console.log(`Swap completed: ${result.outputAmount} tokens delivered`);
```

## Web App Integration

The SDK works natively in the browser — no polyfills or Node.js shims needed. For a comprehensive guide, see [Web Integration Guide](./docs/web-integration.md).

### Browser Quick Start (Base → Solana)

```bash
npm install @clawswap/sdk viem
```

```typescript
import { ClawSwapClient, isEvmSource } from '@clawswap/sdk';
import { createWalletClient, createPublicClient, custom, http } from 'viem';
import { base } from 'viem/chains';

// 1. Connect browser wallet (MetaMask, Coinbase Wallet, etc.)
const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' });
const walletClient = createWalletClient({
account,
chain: base,
transport: custom(window.ethereum),
});

// 2. Create SDK client (no x402 payment needed for Base source — it's free)
const client = new ClawSwapClient();

// 3. Execute swap
const swap = await client.executeSwap({
sourceChain: 'base',
sourceToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
destinationChain: 'solana',
destinationToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
amount: '1000000', // 1 USDC
userWallet: account,
recipient: 'your-solana-address',
});

// 4. Sign and submit with browser wallet (MetaMask will pop up)
if (isEvmSource(swap)) {
const publicClient = createPublicClient({ chain: base, transport: http() });
for (const tx of swap.transactions) {
const hash = await walletClient.sendTransaction({
to: tx.to as `0x${string}`,
data: tx.data as `0x${string}`,
value: BigInt(tx.value),
});
await publicClient.waitForTransactionReceipt({ hash });
console.log(`TX confirmed: https://basescan.org/tx/${hash}`);
}
}

// 5. Monitor settlement
const result = await client.waitForSettlement(swap.requestId, {
timeout: 300_000,
onStatusUpdate: (s) => console.log(`Status: ${s.status}`),
});
```

### Integration Approaches

| Approach | Dependencies | Best For |
|----------|-------------|----------|
| **Raw viem** | `viem` | Simple apps, custom wallet UIs |
| **wagmi + ConnectKit** | `wagmi`, `viem`, `connectkit` | Production React/Next.js apps |

See [examples/browser/](./examples/browser/) for raw viem and [examples/browser-wagmi/](./examples/browser-wagmi/) for wagmi v2.

## Supported Frameworks

| Framework | Package | Status |
Expand Down
38 changes: 34 additions & 4 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ pnpm example:node -- status <swapId>

[Full Documentation →](./node-cli/README.md)

### 2. Browser Example
### 2. Browser Example (Raw viem)

Interactive web application with wallet connection.
Interactive web application with direct MetaMask/injected wallet integration.

```bash
# Start dev server
Expand All @@ -66,6 +66,28 @@ pnpm example:browser

[Full Documentation →](./browser/README.md)

### 3. Browser Example (wagmi + ConnectKit)

Production-ready React app with wagmi v2 wallet management. Supports MetaMask, Coinbase Wallet, WalletConnect, and more.

```bash
# Start dev server
pnpm example:browser-wagmi

# Open http://localhost:5174
```

[Full Documentation →](./browser-wagmi/README.md)

### Choosing a Browser Example

| Feature | Raw viem (`browser/`) | wagmi + ConnectKit (`browser-wagmi/`) |
|---------|----------------------|--------------------------------------|
| Wallet support | MetaMask (injected) | MetaMask, Coinbase, WalletConnect, etc. |
| Chain switching | Manual | Automatic |
| Dependencies | `viem` | `wagmi`, `viem`, `connectkit` |
| Best for | Simple apps, non-React | Production React/Next.js |

## Test Modes

The examples support three test modes:
Expand Down Expand Up @@ -117,7 +139,9 @@ examples/
│ └── validators.ts # Input validation
├── node-cli/ # Node.js CLI example
│ └── ...
└── browser/ # Browser example
├── browser/ # Browser example (raw viem)
│ └── ...
└── browser-wagmi/ # Browser example (wagmi + ConnectKit)
└── ...
```

Expand Down Expand Up @@ -151,9 +175,15 @@ CLAWSWAP_API_URL=https://... # Optional: override API URL
TEST_MODE=dry-run # mock | dry-run | full
```

### Browser (`.env`)
### Browser — Raw viem (`.env`)
```bash
VITE_CLAWSWAP_API_URL=https://... # Optional: override API URL
```

### Browser — wagmi (`.env`)
```bash
VITE_CLAWSWAP_API_URL=https://... # Optional: override API URL
VITE_WC_PROJECT_ID=... # Optional: WalletConnect project ID
```

## Running in CI/CD
Expand Down
6 changes: 6 additions & 0 deletions examples/browser-wagmi/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# ClawSwap API URL (optional)
VITE_CLAWSWAP_API_URL=https://api.clawswap.dev

# WalletConnect project ID (optional, for WalletConnect wallets)
# Get one at https://cloud.walletconnect.com
VITE_WC_PROJECT_ID=
93 changes: 93 additions & 0 deletions examples/browser-wagmi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ClawSwap SDK - wagmi v2 + ConnectKit Example

Production-ready browser example using [wagmi v2](https://wagmi.sh) and [ConnectKit](https://docs.family.co/connectkit) for wallet management.

## What This Demonstrates

- **wagmi v2** for wallet connection, chain management, and transaction sending
- **ConnectKit** for a polished wallet connection UI (MetaMask, Coinbase Wallet, WalletConnect, etc.)
- **ClawSwap SDK** for cross-chain swap execution (quote, execute, sign, monitor)
- **Custom `useClawSwap` hook** showing how to bridge the SDK with wagmi

## Prerequisites

- MetaMask, Coinbase Wallet, or other browser wallet
- Base network with USDC (for Base-source swaps)

## Running

From the monorepo root:

```bash
pnpm install
pnpm build
pnpm example:browser-wagmi
```

Open [http://localhost:5174](http://localhost:5174).

## Environment Variables

Create a `.env` file (optional):

```bash
# Override API URL (optional)
VITE_CLAWSWAP_API_URL=https://api.clawswap.dev

# WalletConnect project ID (optional, needed for WalletConnect wallets)
# Get one at https://cloud.walletconnect.com
VITE_WC_PROJECT_ID=your_project_id
```

## Key Files

| File | Description |
|------|-------------|
| `src/config/wagmi.ts` | wagmi configuration with Base chain and connectors |
| `src/hooks/useClawSwap.ts` | Custom hook wrapping ClawSwap SDK with wagmi wallet/public clients |
| `src/components/SwapForm.tsx` | Combined quote + execute form component |
| `src/components/SwapProgress.tsx` | Cross-chain settlement status polling |
| `src/main.tsx` | Provider setup (WagmiProvider + QueryClient + ConnectKit) |

## The `useClawSwap` Hook

The key integration pattern — a thin hook (~80 lines) that bridges the SDK with wagmi:

```typescript
import { useWalletClient, usePublicClient } from 'wagmi';
import { ClawSwapClient, isEvmSource } from '@clawswap/sdk';

export function useClawSwap() {
const { data: walletClient } = useWalletClient();
const publicClient = usePublicClient();
const client = useMemo(() => new ClawSwapClient(), []);

const executeAndSign = useCallback(async (params) => {
const response = await client.executeSwap(params);

if (isEvmSource(response)) {
for (const tx of response.transactions) {
const hash = await walletClient.sendTransaction({
to: tx.to, data: tx.data, value: BigInt(tx.value),
});
await publicClient.waitForTransactionReceipt({ hash });
}
}

return response;
}, [walletClient, publicClient, client]);

return { client, executeAndSign };
}
```

## Comparison: This vs Raw viem Example

| Feature | This (wagmi) | Raw viem (`examples/browser/`) |
|---------|-------------|-------------------------------|
| Wallet connection | ConnectKit UI | Manual `window.ethereum` |
| Supported wallets | MetaMask, Coinbase, WalletConnect, etc. | Injected only (MetaMask) |
| Chain switching | Automatic via wagmi | Manual `wallet_switchEthereumChain` |
| Reconnection | Automatic | Manual |
| Dependencies | wagmi, connectkit, @tanstack/react-query | viem only |
| Best for | Production React/Next.js apps | Simple apps, non-React frameworks |
35 changes: 35 additions & 0 deletions examples/browser-wagmi/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ClawSwap SDK - wagmi Example</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: #0f172a;
min-height: 100vh;
padding: 20px;
color: #e2e8f0;
}

code {
font-family: 'Monaco', 'Courier New', monospace;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading