npm package: @loomlay/openclaw-wallet-sdk
Description: TypeScript SDK for the LoomLay Agent API - wallet management, trading, and DEX data for AI agents
Author: LoomLay
Latest version: 0.1.3

# @loomlay/openclaw-wallet-sdk

TypeScript SDK for the LoomLay Agent API - wallet management, trading, and DEX data for AI agents.

## Features

- **Self-Custody**: Private keys encrypted on your device, never sent to server
- **Zero-config**: Auto-registers API key, local wallet generation
- **Fluent API**: `wallet.trading.swap()`, `wallet.dex.trending()`
- **Full TypeScript types**: Complete type definitions for all endpoints
- **Natural amounts**: Supports `"1.5"`, `"$100"`, `"50%"`, `"max"`
- **Typed errors**: Error classes with codes for proper handling
- **WebSocket support**: Real-time DEX data and chain subscriptions

## Installation

### For AI Agents (via ClawHub)

```bash
clawhub install openclaw-wallet --registry https://clawhub.ai
```

This installs the skill and makes all 27 tools available to your agent automatically.

### For Programmatic Use (via npm)

```bash
npm install @loomlay/openclaw-wallet-sdk
```

## Quick Start

### Self-Custody Mode (Recommended)

```typescript
import { OpenClawWallet } from '@loomlay/openclaw-wallet-sdk';

const wallet = new OpenClawWallet({
  apiKey: 'agent_xxx',
  walletMode: 'local',
  getPassphrase: async () => process.env.LOOMLAY_WALLET_PASSPHRASE!,
});

// Create a wallet — keys generated and encrypted locally
const created = await wallet.wallet.create();
console.log('Seed phrase:', created.seedPhrase); // Save securely!

// Swap tokens — signs locally, submits via API
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '1.5'
});
```

### Custodial Mode

```typescript
import { OpenClawWallet } from '@loomlay/openclaw-wallet-sdk';

// Register for an API key (once per IP)
const { apiKey } = await OpenClawWallet.register();

// Create the client — server manages keys
const wallet = new OpenClawWallet({ apiKey });

// Create a wallet
const created = await wallet.wallet.create();
console.log('Seed phrase:', created.seedPhrase);

// Swap tokens
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '1.5'
});
```

## API Reference

### Initialization

```typescript
import { OpenClawWallet } from '@loomlay/openclaw-wallet-sdk';

const wallet = new OpenClawWallet({
  apiKey: 'agent_xxx',           // Required
  baseUrl: 'https://api.loomlay.com', // Optional (default)
  timeout: 30000,                // Optional: request timeout in ms
  maxRetries: 3,                 // Optional: retry count
  retryDelay: 1000,              // Optional: base retry delay in ms
  walletMode: 'local',           // Optional: 'custodial' (default) or 'local'
  getPassphrase: async () => '...', // Required for local mode
});
```

### Wallet Modes

| Mode | Keys Stored | Signing | Best For |
|------|-------------|---------|----------|
| `custodial` | Server-side (PostgreSQL) | Server | Simple integration |
| `local` | Client-side (`~/.loomlay/wallet.json`) | Client | Self-custody, maximum security |

In `local` mode:
- `wallet.create()` generates keys locally and registers public addresses with the API
- `trading.swap()` builds an unsigned tx via API → signs locally → submits signed tx
- `trading.transfer()` builds an unsigned tx via API → signs locally → submits via RPC proxy
- `trading.bridge()` always uses custodial mode (EVM signing not yet supported locally)

### Registration

```typescript
// Register for an API key (rate limited by IP)
const result = await OpenClawWallet.register();
console.log('API Key:', result.apiKey);
console.log('Account ID:', result.accountId);
```

### Wallet Management

```typescript
// Create a wallet (local mode: keys generated on device)
const created = await wallet.wallet.create();
// Returns: { wallet: { solanaAddress, evmAddress }, seedPhrase, message }

// Get wallet info and balances
const info = await wallet.wallet.get();
console.log('SOL balance:', info.balances.solana.sol);
console.log('ETH balance:', info.balances.evm.eth);

// Export private keys
// Local mode: decrypts locally using passphrase
// Custodial mode: requires seed phrase
const keys = await wallet.wallet.exportKeys('your seed phrase here');
console.log('Solana key:', keys.solanaPrivateKey);
console.log('EVM key:', keys.evmPrivateKey);

// Import an existing seed phrase (local mode only)
const imported = await wallet.wallet.importSeed(
  'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
  'my-passphrase'
);
console.log('Imported:', imported.wallet.solanaAddress);

// Register an external wallet with the API (local mode)
await wallet.wallet.register({
  solanaAddress: 'your-solana-address',
  evmAddress: '0xyour-evm-address', // Optional
});
```

### Trading

#### Swaps

```typescript
// Decimal amount
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '1.5'
});

// USD amount
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '$100'
});

// Percentage of balance
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '50%'
});

// Max (all tokens)
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: 'max'
});

// Get quote without executing
const quote = await wallet.trading.getSwapQuote({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '1'
});
console.log('Output:', quote.outputAmount);
console.log('Price impact:', quote.priceImpact);
```

#### Transfers

```typescript
await wallet.trading.transfer({
  token: 'SOL',
  amount: '0.1',
  to: 'recipient_address',
  chain: 'solana' // Optional, default: solana
});
```

#### Bridges

```typescript
// Get bridge quote
const quote = await wallet.trading.getBridgeQuote({
  inputToken: 'SOL',
  amount: '1',
  sourceChain: 'solana',
  destinationChain: 'base'
});

// Execute bridge
const result = await wallet.trading.bridge({
  inputToken: 'SOL',
  amount: '1',
  sourceChain: 'solana',
  destinationChain: 'base'
});
```

### Token Information

```typescript
// Search tokens
const results = await wallet.tokens.search('BONK');

// Get token price
const price = await wallet.tokens.getPrice('SOL');
console.log('SOL price:', price.price);

// Get token details
const details = await wallet.tokens.getDetails('token_address');

// Get chart data
const chart = await wallet.tokens.getChart('token_address');
```

### Portfolio

```typescript
// Get combined portfolio
const portfolio = await wallet.portfolio.get();
console.log('Total value:', portfolio.totalUsdValue);

// Get transaction history
const history = await wallet.portfolio.getHistory({
  limit: 50,
  chain: 'solana' // Optional filter
});
```

### DEX Data

```typescript
// Get trending pairs
const trending = await wallet.dex.trending({
  chain: 'solana',
  minLiquidity: 10000,
  limit: 20
});

// Get top volume pairs
const volume = await wallet.dex.volume({ chain: 'solana' });

// Get gainers/losers
const gainers = await wallet.dex.gainers({ chain: 'solana' });
const losers = await wallet.dex.losers({ chain: 'solana' });

// Get new pairs (< 24h)
const newPairs = await wallet.dex.new({ chain: 'solana' });

// Get Pumpfun trending
const pumpfun = await wallet.dex.pumpfun({ maxAge: 24 });

// Advanced query
const results = await wallet.dex.query({
  chain: 'solana',
  timeframe: 'h24',
  rankBy: 'volume',
  order: 'desc',
  filters: {
    liquidity: { min: 50000 },
    volume24h: { min: 100000 }
  },
  minSafetyScore: 50,
  limit: 100
});
```

### Token Launch

```typescript
// Launch a token
const result = await wallet.tokenize.launch({
  name: 'My Token',
  symbol: 'MYT',
  tier: '100k', // Market cap tier
  imageUrl: 'https://...' // Optional
});
console.log('Token mint:', result.tokenMint);
console.log('Pool address:', result.poolAddress);

// Get launched token info
const info = await wallet.tokenize.getInfo();
```

### Fee Management

```typescript
// Get fee status
const status = await wallet.fees.getStatus();
console.log('Unclaimed fees:', status.beneficiaryFeesUnclaimedSol, 'SOL');
console.log('Can claim:', status.canClaim);

// Claim fees
const claim = await wallet.fees.claim();
console.log('Claimed:', claim.amountSol, 'SOL');
```

### RPC Proxy

```typescript
// Make RPC calls
const balance = await wallet.rpc.call('solana', 'getBalance', [address]);
console.log('Balance:', balance.result);

// Get supported chains
const chains = await wallet.rpc.getChains();
```

### WebSocket: DEX Data

```typescript
const dexWs = wallet.createDexWebSocket();
await dexWs.connect();

// Subscribe to trending pairs
const subId = await dexWs.subscribe(
  { chain: 'solana', minLiquidity: 10000 },
  (pairs) => console.log('Snapshot:', pairs.length, 'pairs'),
  (diff) => console.log('Update:', diff.added.length, 'new pairs')
);

// Unsubscribe
dexWs.unsubscribe(subId);
dexWs.disconnect();
```

### WebSocket: Chain RPC

```typescript
const chainWs = wallet.createChainWebSocket('solana');
await chainWs.connect();

// Make RPC call
const slot = await chainWs.call<number>('getSlot');

// Subscribe to updates
const subId = await chainWs.subscribe(
  'accountSubscribe',
  [address],
  (data) => console.log('Account changed:', data)
);

// Unsubscribe
await chainWs.unsubscribe(subId);
chainWs.disconnect();
```

## Error Handling

```typescript
import {
  ApiError,
  RateLimitError,
  NetworkError,
  TimeoutError,
  WebSocketError
} from '@loomlay/openclaw-wallet-sdk';

try {
  await wallet.trading.swap({ ... });
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log('Rate limited, retry in', error.retryAfter, 'seconds');
  } else if (error instanceof ApiError) {
    console.log('API error:', error.message);
    console.log('Code:', error.code);
    console.log('Status:', error.status);
  } else if (error instanceof NetworkError) {
    console.log('Network error:', error.message);
  } else if (error instanceof TimeoutError) {
    console.log('Request timed out');
  }
}
```

### Error Codes

| Code | Description |
|------|-------------|
| `BAD_REQUEST` | Invalid request parameters |
| `UNAUTHORIZED` | Missing or invalid API key |
| `FORBIDDEN` | Action not allowed |
| `NOT_FOUND` | Resource not found |
| `CONFLICT` | Resource already exists |
| `RATE_LIMITED` | Too many requests |
| `INTERNAL_ERROR` | Server error |

## Supported Chains

| Chain | Swaps | Bridges | RPC |
|-------|-------|---------|-----|
| Solana | ✅ | ✅ | ✅ |
| Ethereum | ✅ | ✅ | ✅ |
| Base | ✅ | ✅ | ✅ |
| Arbitrum | ✅ | ✅ | ✅ |
| Optimism | ✅ | ✅ | ✅ |
| Polygon | ✅ | ✅ | ✅ |
| BSC | ✅ | ✅ | ✅ |

## Amount Formats

The SDK accepts flexible amount formats:

| Format | Example | Description |
|--------|---------|-------------|
| Decimal | `"1.5"` | Direct amount |
| USD | `"$100"` or `"100usd"` | Dollar amount (converted at current price) |
| Percentage | `"50%"` | Percentage of balance |
| Max | `"max"` or `"all"` | Entire balance |

## Plugin Package

For AI agents that need native tool integration, use the plugin package:

```bash
# Via ClawHub (recommended for agents)
clawhub install openclaw-wallet --registry https://clawhub.ai

# Via npm (for programmatic integration)
npm install @loomlay/openclaw-wallet-plugin
```

The plugin provides:
- **29 native tools** - Ready-to-use functions for wallets, trading, DEX data, and token launches
- **Self-custody by default** - Keys generated and stored locally, never sent to server
- **SKILL.md** - Comprehensive training material for AI agents
- **Standardized responses** - Consistent `{ success, data, error }` format

See [`plugin/README.md`](./plugin/README.md) for full plugin documentation.

## Security

### Self-Custody (Local Mode)

- **Encryption**: PBKDF2-SHA512 (600k iterations) + AES-256-GCM with random salt and IV
- **Storage**: `~/.loomlay/wallet.json` with `0600` permissions (owner read/write only)
- **Passphrase**: Never written to disk — in-memory only via env var or `getPassphrase` callback
- **Transaction validation**: Fee payer verified before signing to prevent malicious transactions
- **Key zeroing**: Private key buffers zeroed after signing operations

### General

- **API Key**: Store in environment variables, never hardcode
- **Seed Phrase**: Returned once from `wallet_create`, store offline securely
- **Quotes First**: Always get quotes before executing trades
- **Verify Addresses**: Double-check recipient addresses for transfers

## License

MIT