版本: v1.0.0
📌 重要说明:本文档聚焦 JS/TS SDK 视角的客户端应用开发指南。
如需了解 WES 平台的核心概念、架构设计、交易模型等,请参考主仓库文档。
本文档目标:
- 说明如何使用 JS/TS SDK 开发 WES 客户端应用
- 讲解常见开发模式(客户端初始化、业务服务使用、交易构建、事件订阅等)
- 提供从安装到部署的完整开发流程
- 引用平台文档:平台概念(UTXO、交易模型等)请参考主仓库文档
前置阅读(平台级文档,来自主仓库):
- WES 系统架构文档 - 系统架构总览
- JSON-RPC API 规范 - API 规范说明
- 交易模型文档 - UTXO 交易模型详解
- Node.js 20+ - 用于开发环境
- TypeScript 5.0+ - 用于类型检查(可选但推荐)
npm install @weisyn/client-sdk-js
# 或
yarn add @weisyn/client-sdk-js
# 或
pnpm add @weisyn/client-sdk-jsimport { Client, TokenService, Wallet } from '@weisyn/client-sdk-js';
// 1. 初始化客户端
const client = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
});
// 2. 创建钱包
const wallet = Wallet.fromPrivateKey('0x...');
// 3. 创建 Token 服务
const tokenService = new TokenService(client, wallet);
// 4. 执行转账
const result = await tokenService.transfer({
from: wallet.address,
to: '0x...',
amount: 1000000, // 1 WES (假设 6 位小数)
tokenId: null, // null 表示原生币
});
console.log(`转账成功!交易哈希: ${result.txHash}`);<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@weisyn/client-sdk-js/dist/index.umd.js"></script>
</head>
<body>
<script>
const { Client, TokenService, Wallet } = WESClientSDK;
const client = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
});
// ... 使用 SDK
</script>
</body>
</html>SDK 支持两种传输协议(浏览器环境不支持 gRPC):
// HTTP 客户端(最常用)
const client = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
timeout: 30000,
});
// WebSocket 客户端(用于事件订阅)
const wsClient = new Client({
endpoint: 'ws://localhost:28681',
protocol: 'websocket',
});WESClient 提供类型化的 RPC 封装,推荐使用:
import { WESClient } from '@weisyn/client-sdk-js';
// 创建 WESClient
const wesClient = new WESClient({
endpoint: 'http://localhost:28680',
protocol: 'http',
});
// UTXO 操作
const utxos = await wesClient.listUTXOs(address);
// 资源操作
const resource = await wesClient.getResource(resourceId);
const resources = await wesClient.getResources({
resourceType: 'contract',
limit: 20,
});
// 交易操作
const tx = await wesClient.getTransaction(txId);
const txHistory = await wesClient.getTransactionHistory({
resourceId: resourceId,
limit: 100,
});
// 事件操作
const events = await wesClient.getEvents({
resourceId: resourceId,
limit: 50,
});所有业务服务都遵循相同的设计模式:
// 创建服务实例(方式1:使用 WESClient)
const wesClient = new WESClient(cfg);
const tokenService = new TokenService(wesClient);
// 创建服务实例(方式2:使用底层 Client + Wallet)
const client = new Client(cfg);
const wallet = Wallet.fromPrivateKey('0x...');
const tokenService = new TokenService(client, wallet);
// 调用业务方法
const result = await tokenService.transfer({
from: wallet.address,
to: toAddr,
amount: 1000,
tokenId: null, // null = 原生币
});sequenceDiagram
participant App as 应用层
participant Service as Service 层 (L3)
participant Builder as TransactionBuilder
participant Client as WESClient (L1)
participant Wallet as Wallet
participant Node as WES 节点
App->>Service: transfer(...)
Service->>Builder: buildTransaction(...)
Builder->>Client: listUTXOs(...)
Client->>Node: wes_getUTXO RPC
Node-->>Client: UTXO[]
Client-->>Builder: UTXO[]
Builder->>Builder: 构造交易草稿 (DraftJSON)
Builder->>Client: wes_buildTransaction RPC
Client->>Node: wes_buildTransaction RPC
Node-->>Client: UnsignedTx
Client-->>Builder: UnsignedTx
Builder-->>Service: UnsignedTx
Service->>Wallet: signTransaction(unsignedTx)
Wallet-->>Service: SignedTx
Service->>Client: submitTransaction(signedTx)
Client->>Node: wes_sendRawTransaction RPC
Node-->>Client: TxHash
Client-->>Service: TxHash
Service-->>App: TxHash
// 单客户端模式
const client = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
});
// 多客户端模式(HTTP + WebSocket)
const httpClient = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
});
const wsClient = new Client({
endpoint: 'ws://localhost:28681',
protocol: 'websocket',
});// 模式 1:使用 WESClient(类型化 API,推荐)
const wesClient = new WESClient(cfg);
const resourceService = new ResourceService(wesClient);
const resources = await resourceService.getResources(filters);
// 模式 2:使用业务服务(业务语义 API)
const tokenService = new TokenService(client, wallet);
const result = await tokenService.transfer(req);// 创建新钱包
const wallet = Wallet.create();
// 从私钥创建钱包
const wallet = Wallet.fromPrivateKey('0x...');
// 从 Keystore 加载钱包
const wallet = await Wallet.loadFromKeystore(keystorePath, password);
// 获取地址
const address = wallet.address; // Uint8Array (20 字节)
// 签名交易
const signedTx = await wallet.signTransaction(unsignedTxBytes);try {
const result = await tokenService.transfer(req);
} catch (error) {
// 检查错误类型
if (error instanceof WESClientError) {
switch (error.code) {
case 'NETWORK_ERROR':
// 网络错误处理(可重试)
console.error('网络错误:', error);
break;
case 'INVALID_PARAMS':
// 参数错误处理(不可重试)
console.error('参数错误:', error);
break;
case 'RPC_ERROR':
// RPC 错误处理
console.error('RPC 错误:', error);
break;
default:
// 其他错误处理
console.error('未知错误:', error);
}
} else {
// 非 WESClientError 错误
console.error('其他错误:', error);
}
}// 使用 WebSocket 客户端订阅事件
const wsClient = new WESClient({
endpoint: 'ws://localhost:28681',
protocol: 'websocket',
});
const subscription = await wsClient.subscribeEvents({
resourceId: resourceId,
eventName: eventName,
});
subscription.on('event', (event) => {
console.log(`收到事件: ${event.topic}, 数据: ${event.data}`);
});// 浏览器环境:使用 Web Crypto API
if (typeof window !== 'undefined') {
// 浏览器环境
const wallet = Wallet.create(); // 使用 Web Crypto API
}
// Node.js 环境:使用 crypto 模块
if (typeof window === 'undefined') {
// Node.js 环境
const wallet = Wallet.create(); // 使用 crypto 模块
}interface ClientConfig {
endpoint: string; // 节点地址
protocol: 'http' | 'websocket'; // 协议类型(浏览器不支持 gRPC)
timeout?: number; // 超时时间(毫秒)
retry?: RetryConfig; // 重试配置
logger?: Logger; // 日志器(可选)
debug?: boolean; // 调试模式(可选)
}- HTTP:最常用,适合大多数场景
- WebSocket:实时事件订阅,适合需要实时数据的应用
- gRPC:❌ 浏览器环境不支持(仅 Node.js 环境支持,但 JS SDK 暂未实现)
// 查询地址下的所有 UTXO
const utxos = await wesClient.listUTXOs(address);
for (const utxo of utxos) {
console.log(`UTXO: ${utxo.txId}:${utxo.outputIndex}, 金额: ${utxo.amount}`);
}// 查询单个资源
const resource = await wesClient.getResource(resourceId);
// 查询资源列表(带过滤)
const resources = await wesClient.getResources({
resourceType: 'contract',
owner: ownerAddr,
limit: 20,
offset: 0,
});// 查询单个交易
const tx = await wesClient.getTransaction(txId);
// 查询交易历史
const txHistory = await wesClient.getTransactionHistory({
resourceId: resourceId,
limit: 100,
offset: 0,
});const tokenService = new TokenService(client, wallet);
// 单笔转账
const result = await tokenService.transfer({
from: wallet.address,
to: toAddr,
amount: 1000,
tokenId: null, // null = 原生币
});
// 批量转账
const result = await tokenService.batchTransfer({
from: wallet.address,
transfers: [
{ to: addr1, amount: 100, tokenId: tokenID },
{ to: addr2, amount: 200, tokenId: tokenID },
],
});
// 代币铸造
const result = await tokenService.mint({
to: recipientAddr,
amount: 10000,
tokenId: tokenID,
contractAddr: contractAddr,
});
// 查询余额
const balance = await tokenService.getBalance(address, tokenID);const resourceService = new ResourceService(wesClient);
// 部署合约(支持锁定条件)
const result = await resourceService.deployContract({
from: wallet.address,
wasmContent: wasmBytes,
contractName: 'MyContract',
initArgs: initArgs,
lockingConditions: [
{
type: 'SingleKey',
keys: [wallet.address],
},
],
}, wallet);业务服务会自动处理交易构建和签名,开发者无需关心底层细节:
- 构建交易草稿:Service 层根据业务参数构建
DraftJSON - 调用节点 API:调用
wes_buildTransaction获取未签名交易 - Wallet 签名:使用 Wallet 对交易进行签名
- 完成交易:调用
wes_finalizeTransactionFromDraft完成交易 - 提交交易:调用
wes_sendRawTransaction提交已签名交易
// 创建 WebSocket 客户端
const wsClient = new WESClient({
endpoint: 'ws://localhost:28681',
protocol: 'websocket',
});
// 订阅事件
const subscription = await wsClient.subscribeEvents({
resourceId: resourceId,
eventName: eventName,
});
// 处理事件流
subscription.on('event', (event) => {
console.log(`收到事件: ${event.topic}, 数据: ${event.data}`);
});// 创建新钱包
const wallet = Wallet.create();
// 保存到 Keystore
await wallet.saveToKeystore(keystorePath, password);
// 从 Keystore 加载
const wallet = await Wallet.loadFromKeystore(keystorePath, password);// WESClientError 统一错误类型
class WESClientError extends Error {
code: WESClientErrorCode;
message: string;
cause?: Error;
}
// 错误码
type WESClientErrorCode =
| 'NETWORK_ERROR'
| 'RPC_ERROR'
| 'INVALID_PARAMS'
| 'RPC_NOT_IMPLEMENTED'
| 'NOT_FOUND'
| 'DECODE_FAILED';// HTTP 客户端自动管理连接
const client = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
timeout: 30000,
});// 批量查询 UTXO(并发调用)
// 通过地址查询所有 UTXO(地址模型,与节点 API 对齐)
const utxos = await wesClient.listUTXOs(address);
// 批量查询资源
const resources = await wesClient.batchGetResources(resourceIDs);SDK 提供完整的 TypeScript 类型定义:
import { Client, TokenService, Wallet, WESClient } from '@weisyn/client-sdk-js';
// 类型安全
const client: Client = new Client({
endpoint: 'http://localhost:28680',
protocol: 'http',
});
// 类型推断
const wallet = Wallet.fromPrivateKey('0x...');
// wallet 类型自动推断为 Wallet// 浏览器环境使用 Web Crypto API
if (typeof window !== 'undefined') {
const crypto = window.crypto;
// 使用 Web Crypto API 进行加密操作
}浏览器环境需要配置 CORS 才能访问节点 API:
// 确保节点 API 支持 CORS
const client = new Client({
endpoint: 'https://api.example.com:28680', // 使用 HTTPS
protocol: 'http',
});- API 参考 - 详细的 API 文档
- 业务场景实现指南 - 业务场景实现示例
- SDK 架构 - SDK 架构设计
- 语言与环境限制 - JS/TS 特有限制
- WES 系统架构文档 - 平台架构(主仓库)
- Client API 设计 - WESClient API 详细设计
- Services 设计 - 服务层详细设计
维护者: WES Core Team