poseidon-otc
# Poseidon OTC Skill
**TL;DR for Agents:** This skill lets you trade tokens with humans or other agents on Solana. You create a room, both parties deposit tokens to escrow, confirm, and execute an atomic swap. No trust required - it's all on-chain.
## When to Use This Skill
- **Trading tokens P2P** - Swap any SPL token directly with another party
- **Agent-to-agent commerce** - Two AI agents can negotiate and execute trades autonomously
- **Large OTC deals** - Avoid slippage from DEX trades by going direct
- **Protected trades** - Use lockups to prevent counterparty from dumping immediately
- **Multi-token swaps** - Trade up to 4 tokens per side in one atomic transaction
## Quick Start for Agents
### 1. Initialize (requires wallet)
```typescript
import { PoseidonOTC } from 'poseidon-otc-skill';
const client = new PoseidonOTC({
burnerKey: process.env.POSEIDON_BURNER_KEY // base58 private key
});
```
### 2. Create a Trade Room
```typescript
const { roomId, link } = await client.createRoom();
// Share `link` with counterparty or another agent
```
### 3. Wait for Counterparty & Set Offer
```typescript
// Check room status
const room = await client.getRoom(roomId);
// Set what you're offering (100 USDC example)
await client.updateOffer(roomId, [{
mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC mint
amount: 100000000, // 100 USDC (6 decimals)
decimals: 6
}]);
```
### 4. Confirm & Execute
```typescript
// First confirmation = "I agree to these terms"
await client.confirmTrade(roomId, 'first');
// After deposits, second confirmation
await client.confirmTrade(roomId, 'second');
// Execute the atomic swap
const { txSignature } = await client.executeSwap(roomId);
```
## Complete Trade Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ TRADE LIFECYCLE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. CREATE ROOM │
│ └─> Party A calls createRoom() │
│ Returns: roomId, shareable link │
│ │
│ 2. JOIN ROOM │
│ └─> Party B calls joinRoom(roomId) │
│ Room now has both participants │
│ │
│ 3. SET OFFERS │
│ └─> Both parties call updateOffer(roomId, tokens) │
│ Each specifies what they're putting up │
│ │
│ 4. FIRST CONFIRM (agree on terms) │
│ └─> Both call confirmTrade(roomId, 'first') │
│ "I agree to swap my X for your Y" │
│ │
│ 5. DEPOSIT TO ESCROW │
│ └─> Tokens move to on-chain escrow │
│ (Handled by frontend or depositToEscrow) │
│ │
│ 6. SECOND CONFIRM (verify deposits) │
│ └─> Both call confirmTrade(roomId, 'second') │
│ "I see the deposits, ready to swap" │
│ │
│ 7. EXECUTE SWAP │
│ └─> Either party calls executeSwap(roomId) │
│ Atomic on-chain swap via relayer │
│ Returns: txSignature │
│ │
│ [OPTIONAL] LOCKUP FLOW │
│ └─> Before step 4, Party A can proposeLockup(roomId, secs) │
│ └─> Party B must acceptLockup(roomId) to continue │
│ └─> After execute, locked tokens claimed via claimLockedTokens │
│ │
└─────────────────────────────────────────────────────────────────┘
```
## API Reference
### Room Management
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `createRoom(options?)` | `{ inviteCode?: string }` | `{ roomId, link }` | Create new room |
| `getRoom(roomId)` | `roomId: string` | `TradeRoom` | Get full room state |
| `getUserRooms(wallet?)` | `wallet?: string` | `TradeRoom[]` | List your rooms |
| `joinRoom(roomId, inviteCode?)` | `roomId, inviteCode?` | `{ success }` | Join as Party B |
| `cancelRoom(roomId)` | `roomId: string` | `{ success }` | Cancel & refund |
| `getRoomLink(roomId)` | `roomId: string` | `string` | Get share URL |
### Trading
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `updateOffer(roomId, tokens)` | `roomId, [{mint, amount, decimals}]` | `{ success }` | Set your offer |
| `withdrawFromOffer(roomId, tokens)` | `roomId, tokens[]` | `{ success }` | Pull back tokens |
| `confirmTrade(roomId, stage)` | `roomId, 'first'│'second'` | `{ success }` | Confirm stage |
| `executeSwap(roomId)` | `roomId: string` | `{ txSignature }` | Execute swap |
| `declineOffer(roomId)` | `roomId: string` | `{ success }` | Reject terms |
### Lockups (Anti-Dump)
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `proposeLockup(roomId, seconds)` | `roomId, seconds` | `{ success }` | Propose lock |
| `acceptLockup(roomId)` | `roomId: string` | `{ success }` | Accept lock |
| `getLockupStatus(roomId)` | `roomId: string` | `{ canClaim, timeRemaining }` | Check timer |
| `claimLockedTokens(roomId)` | `roomId: string` | `{ txSignature }` | Claim after expiry |
### Utility
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `getBalance()` | none | `{ sol: number }` | Check SOL balance |
| `isAutonomous()` | none | `boolean` | Has signing wallet? |
| `getWebSocketUrl()` | none | `string` | Get WS endpoint |
## WebSocket Real-Time Updates
**Don't poll. Subscribe.**
Instead of repeatedly calling `getRoom()`, connect to WebSocket for instant updates:
**Endpoint:** `wss://poseidon.cash/ws/trade-room`
### Subscribe to Room Events
```typescript
const { unsubscribe } = await client.subscribeToRoom(roomId, (event) => {
switch (event.type) {
case 'join':
console.log('Counterparty joined!');
break;
case 'offer':
console.log('Offer updated:', event.data.tokens);
break;
case 'confirm':
console.log('Confirmation received');
break;
case 'execute':
console.log('Swap complete! TX:', event.data.txSignature);
break;
case 'cancel':
console.log('Trade cancelled');
break;
}
});
```
### Event Types
| Event | When It Fires |
|-------|--------------|
| `full-state` | Immediately on subscribe - complete room state |
| `join` | Counterparty joined the room |
| `offer` | Someone updated their offer |
| `confirm` | Someone confirmed (first or second) |
| `lockup` | Lockup proposed or accepted |
| `execute` | Swap executed successfully |
| `cancel` | Room was cancelled |
| `terminated` | Room expired or terminated |
| `error` | Something went wrong |
### WebSocket Actions (Faster than HTTP)
```typescript
await client.sendOfferViaWs(roomId, tokens); // Update offer
await client.sendConfirmViaWs(roomId, 'first'); // Confirm
await client.sendLockupProposalViaWs(roomId, 3600); // Propose 1hr lock
await client.sendAcceptLockupViaWs(roomId); // Accept lock
await client.sendExecuteViaWs(roomId); // Execute swap
```
## Agent-to-Agent Trading Example
**Scenario:** Agent A wants to sell 1000 USDC for 5 SOL to Agent B
### Agent A (Seller):
```typescript
// 1. Create room
const { roomId } = await client.createRoom();
// 2. Set offer (1000 USDC)
await client.updateOffer(roomId, [{
mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
amount: 1000000000, // 1000 USDC
decimals: 6
}]);
// 3. Share roomId with Agent B via your inter-agent protocol
// 4. Subscribe to updates
await client.subscribeToRoom(roomId, async (event) => {
if (event.type === 'offer') {
// Check if Agent B's offer is acceptable (5 SOL)
const room = await client.getRoom(roomId);
if (room.partyBTokenSlots?.[0]?.amount >= 5 * 1e9) {
await client.confirmTrade(roomId, 'first');
}
}
if (event.type === 'confirm' && room.partyBFirstConfirm) {
await client.confirmTrade(roomId, 'second');
}
});
```
### Agent B (Buyer):
```typescript
// 1. Join the room
await client.joinRoom(roomId);
// 2. Set offer (5 SOL)
await client.updateOffer(roomId, [{
mint: 'So11111111111111111111111111111111111111112', // wSOL
amount: 5000000000, // 5 SOL
decimals: 9
}]);
// 3. Subscribe and react
await client.subscribeToRoom(roomId, async (event) => {
if (event.type === 'confirm') {
const room = await client.getRoom(roomId);
if (room.partyAFirstConfirm && !room.partyBFirstConfirm) {
await client.confirmTrade(roomId, 'first');
}
if (room.partyASecondConfirm && room.partyBSecondConfirm) {
// Both confirmed, execute!
await client.executeSwap(roomId);
}
}
});
```
## Common Token Mints
| Token | Mint Address | Decimals |
|-------|--------------|----------|
| USDC | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | 6 |
| USDT | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` | 6 |
| wSOL | `So11111111111111111111111111111111111111112` | 9 |
| BONK | `DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263` | 5 |
## Environment Variables
```bash
POSEIDON_BURNER_KEY=<base58-private-key> # Required for autonomous mode
POSEIDON_API_URL=https://poseidon.cash # API endpoint (default: mainnet)
POSEIDON_RPC_URL=https://api.mainnet-beta.solana.com # Solana RPC
```
## Security Notes
- **Escrow is on-chain** - Funds are held by the Solana program, not the API
- **Atomic swaps** - Either both sides complete or neither does
- **Signatures expire** - Auth signatures valid for 24 hours
- **Lockups are enforced on-chain** - Can't bypass the timer
- **Hot wallet warning** - Only fund your burner wallet with amounts you're comfortable risking
## Program ID
**Mainnet:** `AfiRReYhvykHhKXhwjhcsXFejHdxqYLk2QLWnjvvLKUN`
## Links
- Website: https://poseidon.cash
- Docs: https://docs.poseidon.cash
标签
skill
ai