@dcprotocol/client
Universal TypeScript SDK for integrating DCP into any AI agent or application. Automatically detects local or relay mode and provides a simple async API.
Installation
npm install @dcprotocol/clientQuick Start
import { createDCPClient } from '@dcprotocol/client';
// Create client (auto-detects local server or relay)
const client = await createDCPClient({
agentName: 'my-trading-bot'
});
// Get wallet address
const { address } = await client.getAddress('solana');
console.log('Solana:', address);
// Sign transaction
const { signed_tx, signature } = await client.signTx({
chain: 'solana',
unsigned_tx: unsignedTxBase64,
amount: 1.5,
currency: 'SOL'
});
// Read credential
const { value } = await client.readCredential({
scope: 'identity.email'
});
console.log('Email:', value);Overview
The DCP client provides a unified interface for both local and remote vault access:
- Local mode: Connects to
@dcprotocol/serveron localhost:8420 - Relay mode: Connects via
@dcprotocol/relayusing pairing token - Auto-detection: Tries local first, falls back to relay if configured
Architecture
LOCAL MODE:
┌─────────────────────┐
│ Your Agent │
│ @dcprotocol/client │
└──────────┬──────────┘
│ HTTP
▼
┌─────────────────────┐
│ @dcprotocol/server │ localhost:8420
└──────────┬──────────┘
▼
┌─────────────────────┐
│ Vault (SQLite) │
└─────────────────────┘
RELAY MODE (VPS):
┌─────────────────────┐
│ Your Agent (VPS) │
│ @dcprotocol/client │
└──────────┬──────────┘
│ WSS
▼
┌─────────────────────┐ ┌─────────────────┐
│ Relay Server │◀────▶│ Desktop Vault │
│ relay.dcp.1ly.store│ │ (Your Machine) │
└─────────────────────┘ └─────────────────┘API Reference
createDCPClient(options)
Create and initialize DCP client.
| Option | Type | Description |
|---|---|---|
agentName | string | Agent identifier for audit logs |
pairingToken | string? | Pairing token for relay mode |
localUrl | string? | Local server URL (default: http://127.0.0.1:8420) |
relayUrl | string? | Relay server URL (default: wss://relay.dcp.1ly.store) |
// Local mode (auto-detect)
const client = await createDCPClient({
agentName: 'my-bot'
});
// Relay mode (VPS)
const client = await createDCPClient({
agentName: 'production-bot',
pairingToken: process.env.DCP_PAIRING_TOKEN
});
// Custom local server
const client = await createDCPClient({
agentName: 'dev-bot',
localUrl: 'http://localhost:3000'
});client.getAddress(chain)
Get public address for a blockchain wallet.
| Parameter | Type | Description |
|---|---|---|
chain | string | 'solana' | 'ethereum' | 'base' |
Returns:
{
address: string; // Public address
chain: string; // Chain name
}Example:
const { address } = await client.getAddress('solana');
console.log(`Solana: ${address}`);
const { address: ethAddress } = await client.getAddress('ethereum');
console.log(`Ethereum: ${ethAddress}`);client.signTx(params)
Sign a blockchain transaction (requires user approval).
| Parameter | Type | Description |
|---|---|---|
chain | string | 'solana' | 'ethereum' | 'base' |
unsigned_tx | string | Base64-encoded unsigned transaction |
amount | number | Transaction amount |
currency | string | 'SOL' | 'ETH' | 'BASE_ETH' | 'USDC' |
recipient | string? | Recipient address (optional) |
Returns:
{
signed_tx: string; // Base64-encoded signed transaction
signature: string; // Transaction signature
}Example:
import { Transaction } from '@solana/web3.js';
// Create unsigned transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: fromAddress,
toPubkey: toAddress,
lamports: 1_500_000_000 // 1.5 SOL
})
);
// Serialize to base64
const unsignedTx = transaction.serialize({ requireAllSignatures: false })
.toString('base64');
// Sign with DCP
const { signed_tx, signature } = await client.signTx({
chain: 'solana',
unsigned_tx: unsignedTx,
amount: 1.5,
currency: 'SOL',
recipient: toAddress.toBase58()
});
console.log(`Signature: ${signature}`);
// Broadcast signed transaction
const txBuffer = Buffer.from(signed_tx, 'base64');
const sig = await connection.sendRawTransaction(txBuffer);
console.log(`TX: ${sig}`);client.readCredential(params)
Read stored credential from vault (requires user approval).
| Parameter | Type | Description |
|---|---|---|
scope | string | Data scope (e.g., "identity.email") |
Returns:
{
value: string; // Decrypted value
scope: string; // Scope identifier
sensitivity: string; // 'standard' | 'sensitive' | 'critical'
}Example:
// Read email
const { value: email } = await client.readCredential({
scope: 'identity.email'
});
// Read API key
const { value: apiKey } = await client.readCredential({
scope: 'api.openai'
});
// Use in API call
const openai = new OpenAI({ apiKey });client.budgetCheck(params)
Check if transaction is within budget limits.
| Parameter | Type | Description |
|---|---|---|
chain | string | 'solana' | 'ethereum' | 'base' |
amount | number | Transaction amount |
currency | string | 'SOL' | 'ETH' | 'BASE_ETH' | 'USDC' |
Returns:
{
allowed: boolean; // Can transaction proceed?
requires_approval: boolean; // Needs user approval?
remaining_daily: number; // Remaining daily budget
remaining_tx: number; // Remaining per-tx budget
reason?: string; // Error reason if not allowed
}Example:
const check = await client.budgetCheck({
chain: 'solana',
amount: 1.5,
currency: 'SOL'
});
if (!check.allowed) {
console.error(`Cannot send: ${check.reason}`);
return;
}
if (check.requires_approval) {
console.log('This will require user approval');
} else {
console.log('Under auto-approve threshold');
}
console.log(`Remaining today: ${check.remaining_daily} SOL`);client.disconnect()
Close client connection (important for relay mode).
await client.disconnect();
Complete Examples
Solana Trading Bot
import { createDCPClient } from '@dcprotocol/client';
import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js';
const SOLANA_RPC = 'https://api.mainnet-beta.solana.com';
async function main() {
// Initialize DCP client
const dcp = await createDCPClient({
agentName: 'solana-trader'
});
// Get Solana address
const { address } = await dcp.getAddress('solana');
console.log(`Wallet: ${address}`);
// Connect to Solana
const connection = new Connection(SOLANA_RPC);
const pubkey = new PublicKey(address);
// Check balance
const balance = await connection.getBalance(pubkey);
console.log(`Balance: ${balance / 1e9} SOL`);
// Send SOL
const recipient = new PublicKey('RECIPIENT_ADDRESS');
const amount = 0.1; // SOL
// Check budget first
const budgetCheck = await dcp.budgetCheck({
chain: 'solana',
amount,
currency: 'SOL'
});
if (!budgetCheck.allowed) {
console.error(`Budget exceeded: ${budgetCheck.reason}`);
return;
}
// Create transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: pubkey,
toPubkey: recipient,
lamports: amount * 1e9
})
);
// Get recent blockhash
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = pubkey;
// Serialize unsigned transaction
const unsignedTx = transaction.serialize({
requireAllSignatures: false
}).toString('base64');
// Sign with DCP
const { signed_tx, signature } = await dcp.signTx({
chain: 'solana',
unsigned_tx: unsignedTx,
amount,
currency: 'SOL',
recipient: recipient.toBase58()
});
console.log(`Signed! Signature: ${signature}`);
// Broadcast
const txBuffer = Buffer.from(signed_tx, 'base64');
const txSig = await connection.sendRawTransaction(txBuffer);
console.log(`Transaction: https://solscan.io/tx/${txSig}`);
// Cleanup
await dcp.disconnect();
}
main().catch(console.error);Ethereum Contract Interaction
import { createDCPClient } from '@dcprotocol/client';
import { ethers } from 'ethers';
async function main() {
const dcp = await createDCPClient({
agentName: 'eth-agent'
});
// Get Ethereum address
const { address } = await dcp.getAddress('ethereum');
console.log(`ETH Address: ${address}`);
// Connect to Ethereum
const provider = new ethers.JsonRpcProvider('https://eth-mainnet.g.alchemy.com/v2/KEY');
// Create transaction
const tx = {
to: '0xRECIPIENT',
value: ethers.parseEther('0.05'),
gasLimit: 21000,
gasPrice: await provider.getFeeData().then(d => d.gasPrice)
};
// Serialize unsigned transaction
const unsignedTx = ethers.Transaction.from(tx).unsignedSerialized;
// Sign with DCP
const { signed_tx } = await dcp.signTx({
chain: 'ethereum',
unsigned_tx: Buffer.from(unsignedTx.slice(2), 'hex').toString('base64'),
amount: 0.05,
currency: 'ETH'
});
// Broadcast
const signedTxHex = '0x' + Buffer.from(signed_tx, 'base64').toString('hex');
const receipt = await provider.broadcastTransaction(signedTxHex);
console.log(`TX: https://etherscan.io/tx/${receipt.hash}`);
await dcp.disconnect();
}
main().catch(console.error);Multi-Chain Agent
import { createDCPClient } from '@dcprotocol/client';
async function main() {
const dcp = await createDCPClient({
agentName: 'multi-chain-bot'
});
// Get all addresses
const chains = ['solana', 'ethereum', 'base'] as const;
const addresses = await Promise.all(
chains.map(async (chain) => {
const { address } = await dcp.getAddress(chain);
return { chain, address };
})
);
console.log('Wallet Addresses:');
addresses.forEach(({ chain, address }) => {
console.log(` ${chain}: ${address}`);
});
// Read API keys
const { value: solscanKey } = await dcp.readCredential({
scope: 'api.solscan'
});
const { value: etherscanKey } = await dcp.readCredential({
scope: 'api.etherscan'
});
console.log('API Keys loaded successfully');
await dcp.disconnect();
}
main().catch(console.error);Environment Variables
| Variable | Default | Description |
|---|---|---|
DCP_LOCAL_URL | http://127.0.0.1:8420 | Local server URL |
DCP_RELAY_URL | wss://relay.dcp.1ly.store | Relay server URL |
DCP_PAIRING_TOKEN | undefined | Pairing token for relay mode |
Error Handling
import { createDCPClient } from '@dcprotocol/client';
async function main() {
const dcp = await createDCPClient({
agentName: 'error-handler-bot'
});
try {
const { signed_tx } = await dcp.signTx({
chain: 'solana',
unsigned_tx: unsignedTx,
amount: 100, // Too high!
currency: 'SOL'
});
} catch (error) {
if (error.message.includes('budget')) {
console.error('Transaction exceeds budget limits');
} else if (error.message.includes('denied')) {
console.error('User denied the request');
} else if (error.message.includes('locked')) {
console.error('Vault is locked');
} else {
console.error('Unexpected error:', error);
}
}
await dcp.disconnect();
}
main().catch(console.error);TypeScript Types
import type {
DCPClient,
GetAddressResult,
SignTxParams,
SignTxResult,
ReadCredentialParams,
ReadCredentialResult,
BudgetCheckParams,
BudgetCheckResult
} from '@dcprotocol/client';
// Chain types
type Chain = 'solana' | 'ethereum' | 'base';
type Currency = 'SOL' | 'ETH' | 'BASE_ETH' | 'USDC';
// Client creation options
interface CreateClientOptions {
agentName: string;
pairingToken?: string;
localUrl?: string;
relayUrl?: string;
}See Also
- @dcprotocol/server - Local REST server
- @dcprotocol/proxy - VPS proxy setup
- @dcprotocol/mcp - MCP integration
- Example Agents - Full working examples