5. Web3.js SDK 使用说明
chainmaker-web3-js 是专为长安链(ChainMaker)区块链网络设计的 JavaScript SDK,定位为 Web3 应用开发的核心工具库。它提供类似 ethers.js 的 API 体验,方便开发者在浏览器或前端环境中安全、便捷地与 ChainMaker 区块链进行交互。
5.1. 主要功能
交易签名:支持 RSA/ECDSA/国密算法,目前所有链上操作均需签名认证,保障安全性。
交易发送:可便捷发起链上交易、合约调用、合约部署等操作。
交易订阅:支持监听链上区块事件,实现实时响应。
链信息查询:获取链配置信息、区块详情、交易详情等。
合约交互:提供合约部署、调用、参数编码等完整能力。
多端支持:兼容浏览器环境,NodeJS 服务端环境,支持代理配置,适配多种前端场景。
5.2. 前置依赖
由于 chainmaker-web3-js 是面向长安链,因此对链会有一些要求,目前需要满足以下前置条件:
ChainMaker 区块链网络,版本
>=2.3.8,原因是 HTTP 代理及链订阅问题在该版本得到了修复,之前版本在使用上存在问题,如没开放跨域,WebSocket订阅。HTTP协议使用Web3JS,链需开启HTTP API服务, 在 chainmaker.yml 配置文件中
开启 HTTP API服务:# restful api gateway gateway: # enable restful api enabled: true
参考文档见这里
如想使用 HTTPS 协议,需要自己使用 Nginx/Caddy 等反向代理工具进行 TLS 终端代理,本身链节点的 gRPC TLS 还是处于关闭状态。
5.3. 快速对比 (ethers.js vs chainmaker.js)
通过几个基本的用法,来方便用户了解 chainmaker-web3-js 与 ethers.js 的用法区别。
| 功能 | ethers.js 示例 | chainmaker-web3-js 示例 | 主要区别 |
|---|---|---|---|
| 获取链配置信息 | provider.getNetwork()无需签名 |
provider.getNetwork()需签名,provider 需 signer/wallet |
chainmaker 所有操作都需签名 |
| 获取交易信息 | provider.getTransaction(txHash) |
provider.getTransaction(txHash) |
chainmaker 需签名,provider 配置 signer |
| 获取区块信息 | provider.getBlock(blockHash) |
provider.getBlock(blockHash) |
chainmaker 需签名,provider 配置 signer |
| 部署合约 | factory.deploy()合约工厂需 wallet |
factory.deploy({ contractName, ... })需指定合约名、版本、运行时等 |
chainmaker 需更多参数,所有操作需签名 |
| 调用合约 | contract.someMethod() |
contract.someMethod() |
chainmaker 需签名,合约实例需 wallet |
| gRPC 代理支持 | 不需要 | 需配置 proxyHost,浏览器端使用的话通过 gRPC-Web 代理,推荐走HTTP方式 |
chainmaker 浏览器端使用配置代理,grpc支持,但首推HTTP |
5.4. 使用
如果是npm方式使用,node推荐为v22及以上版本。这里无明确版本要求,但建议使用最新的LTS版本。
5.4.1. 介绍
web3.providers.Web3Provider
web3.Wallet
npm install @chainmaker/web3js
注意:同时支持CJS/ESM两种模块化规范。
5.4.2. API 使用
5.4.3. 获取链配置信息
// 创建钱包实例
const wallet = new web3.Wallet(privateKey); // 这种wallet叫内部signer,将会自动处理签名逻辑
// 使用带签名器的 provider
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
chainmaker: {
chainId: 'chainmaker_pk',
protocol: 'http',
tlsEnable: false,
signer: wallet
}
});
// 获取网络信息
const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);
console.log('链配置:', network.config);
5.4.4. 获取交易信息
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
chainmaker: {s
chainId: 'chainmaker_pk',
protocol: 'http',
tlsEnable: false,
signer: wallet
}
});
const transaction = await provider.getTransaction('0x1234567890abcdef...');
console.log(transaction);
5.4.5. 获取区块信息
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
chainmaker: {
chainId: 'chainmaker_pk',
protocol: 'http',
tlsEnable: false,
signer: wallet
}
});
const block = await provider.getBlock('blockHash');
console.log(block);
5.4.6. 部署合约
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
chainmaker: {
chainId: 'chainmaker_pk',
protocol: 'http',
tlsEnable: false,
signer: wallet
}
});
const factory = new web3.ContractFactory('contractName', bytecode, {
provider
});
const res = factory.deploy({
contractName: 'fact_contract_name' + Date.now(),
contractVersion: '1.0.0',
runtimeType: 'DOCKER_GO',
params: {}
});
5.4.7. 调用合约
const contract = new web3.Contract(contractAddress, [], wallet);
const tx = await contract.someMethod(/* args */);
5.4.8. 订阅
目前仅支持区块订阅。
async function subscribeBlock() {
_currentBlockListener = (block) => {
console.log(block);
console.log(`新块通知: 块高=${block.getBlockHeight()}`);
};
// 开始订阅
await provider.on(
{
event: 'block',
fromBlock: Number(startBlock),
toBlock: Number(endBlock),
withRWSet: false,
onlyHeader: true
},
_currentBlockListener
);
}
// 如果需要关闭订阅,使用 provider.off('block', _currentBlockListener);
5.4.9. K1 曲线支持
当前ChainMaker K1曲线下的私钥是以hex字符串形式存储的,因此可以直接传入私钥字符串创建 Wallet 实例。
const wallet2 = new Wallet('62edf6740bc60d75763c9b980a9df2da2916b1f9c34149e5582ba566e98fbb64');
5.5. 证书 Cert 模式
证书模式下与 PK 相比,需要增加如下配置,组织 ID/证书文本内容/认证类型
const wallet = new web3.Wallet(privateKey, null, {
certificate: '',
orgId: 'wx-org1.chainmaker.org',
authType: 'PermissionedWithCert'
});
5.6. 结合钱包插件使用
chainmaker-web3-js 支持两种使用方式:
5.6.1. 1. 直接使用 Wallet(内部签名器)
当直接使用 Wallet 传入私钥时,会自动处理签名逻辑:
const wallet = new web3.Wallet(privateKey);
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
chainmaker: {
chainId: 'chainmaker_pk',
protocol: 'http',
tlsEnable: false,
signer: wallet // 内部签名器
}
});
5.6.2. 2. 结合钱包插件使用(外部签名器)
如果想结合浏览器扩展钱包或其他钱包插件使用,可以通过实现一个符合 web3.Signer 接口的适配器类来实现。这与 ethers.js 的 Web3Provider 模式完全一致。
5.6.2.1. 快速示例
import { AbstractSigner } from '@chainmaker/web3js';
// 创建适配器类
class WalletPluginAdapter extends AbstractSigner {
constructor(walletPlugin, provider) {
super(provider);
this.walletPlugin = walletPlugin;
}
async getAddress() {
return await this.walletPlugin.getAddress();
}
async signTransaction(tx) {
const populatedTx = await this.populateTransaction(tx);
return await this.walletPlugin.signTransaction(populatedTx);
}
async signMessage(message) {
return await this.walletPlugin.signMessage(message);
}
async signTypedData(domain, types, value) {
return await this.walletPlugin.signTypedData(domain, types, value);
}
connect(provider) {
return new WalletPluginAdapter(this.walletPlugin, provider);
}
}
// 使用适配器
const walletPlugin = window.chainmakerWallet; // 浏览器扩展注入的钱包对象
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
chainmaker: {
chainId: 'chainmaker_pk',
protocol: 'http',
tlsEnable: false
}
});
const signer = new WalletPluginAdapter(walletPlugin, provider);
// 像使用 ethers.js 一样使用
const address = await signer.getAddress();
const tx = await signer.sendTransaction({ /* ... */ });
5.7. 请求代理
代理配置字段为 proxyHost。这里的代理,仅仅为了保证节点IP还配置为真实的,JS通过转发请求地址来访问链节点,使用上也可以直接配置代理地址,nodeIp指向代理地址,proxyHost不配置。
举几个例子
长安链节点为grpc,未开启HTTP,这里可以搭建一个gRPC-Web的代理,nodeIp还是指向链节点的grpc地址,代理配置为proxyHost,浏览器端即可正常发起请求,nodeIp还可以真实的指向链节点的地址。
长安链节点开启了HTTP服务,nodeIp指向HTTP地址,但本身网络无法直连,这时也可以通过配置proxyHost来走HTTP代理。
const provider = web3.getDefaultProvider('36.110.223.69:11406', {
// nodeIp: "36.110.223.23:12391",
chainmaker: {
chainId: 'chain1',
protocol: 'grpc',
tlsEnable: false,
signer: wallet,
proxyHost: 'https://127.0.0.1:9080'
}
});