@caict/bop-typescript-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +112 -0
- package/package.json +90 -0
- package/src/bop/bop-base/README.md +5 -0
- package/src/bop/bop-base/base.ts +366 -0
- package/src/bop/bop-base/index.ts +83 -0
- package/src/bop/bop-base/permit.ts +116 -0
- package/src/bop/bop-base/test/base.test.ts +867 -0
- package/src/bop/bop-base/test/index.test.ts +69 -0
- package/src/bop/bop-base/test/permit.test.ts +125 -0
- package/src/bop/bop-base/tsconfig.json +8 -0
- package/src/bop/bop-proto/README.md +2 -0
- package/src/bop/bop-proto/bop-ws.proto +266 -0
- package/src/bop/bop-proto/bop-ws.ts +4447 -0
- package/src/bop/bop-proto/bop.proto +898 -0
- package/src/bop/bop-proto/bop.ts +12890 -0
- package/src/bop/bop-proto/tsconfig.json +8 -0
- package/src/bop/bop-ws/index.ts +315 -0
- package/src/bop/bop-ws/sample/sample.ts +107 -0
- package/src/bop/bop-ws/tsconfig.json +8 -0
- package/src/bop/index.ts +14 -0
- package/src/bop-sdk/index.ts +22 -0
- package/src/bop-sdk/interface/abstract-service/abstract-account.ts +23 -0
- package/src/bop-sdk/interface/abstract-service/abstract-chain.ts +9 -0
- package/src/bop-sdk/interface/abstract-service/abstract-contract.ts +16 -0
- package/src/bop-sdk/interface/abstract-service/abstract-ledger.ts +15 -0
- package/src/bop-sdk/interface/abstract-service/abstract-provider.ts +13 -0
- package/src/bop-sdk/interface/abstract-service/abstract-signer.ts +133 -0
- package/src/bop-sdk/interface/abstract-service/abstract-transaction.ts +86 -0
- package/src/bop-sdk/interface/provider-ws.ts +10 -0
- package/src/bop-sdk/interface/provider.ts +22 -0
- package/src/bop-sdk/interface/service/3rd.ts +54 -0
- package/src/bop-sdk/interface/service/account.ts +86 -0
- package/src/bop-sdk/interface/service/chain.ts +27 -0
- package/src/bop-sdk/interface/service/contract.ts +51 -0
- package/src/bop-sdk/interface/service/helper.ts +426 -0
- package/src/bop-sdk/interface/service/ledger.ts +75 -0
- package/src/bop-sdk/interface/service/offline/check/index.js +138 -0
- package/src/bop-sdk/interface/service/offline/common/constant.js +6 -0
- package/src/bop-sdk/interface/service/offline/common/snowFlakeUtils.js +192 -0
- package/src/bop-sdk/interface/service/offline/common/util.js +511 -0
- package/src/bop-sdk/interface/service/offline/exception/customErrors.js +29 -0
- package/src/bop-sdk/interface/service/offline/exception/errors.js +90 -0
- package/src/bop-sdk/interface/service/offline/exception/index.js +5 -0
- package/src/bop-sdk/interface/service/offline/operation/accountCreateOperation.js +28 -0
- package/src/bop-sdk/interface/service/offline/operation/accountSetMetadataOperation.js +44 -0
- package/src/bop-sdk/interface/service/offline/operation/accountSetPrivilegeOperation.js +49 -0
- package/src/bop-sdk/interface/service/offline/operation/contractCreateOperation.js +43 -0
- package/src/bop-sdk/interface/service/offline/operation/contractInvokeOperation.js +42 -0
- package/src/bop-sdk/interface/service/offline/operation/contractInvokeRequestOperation.js +69 -0
- package/src/bop-sdk/interface/service/offline/operation/gasSendOperation.js +29 -0
- package/src/bop-sdk/interface/service/offline/operation/gasSendRequestOperation.js +61 -0
- package/src/bop-sdk/interface/service/offline/operation/index.js +20 -0
- package/src/bop-sdk/interface/service/offline/proto/chain_pb.js +12079 -0
- package/src/bop-sdk/interface/service/offline/proto/common_pb.js +2867 -0
- package/src/bop-sdk/interface/service/offline/transaction/index.js +988 -0
- package/src/bop-sdk/interface/service/offline/transaction/operations.js +188 -0
- package/src/bop-sdk/interface/service/offline/validate/account.js +152 -0
- package/src/bop-sdk/interface/service/offline/validate/contract.js +101 -0
- package/src/bop-sdk/interface/service/offline/validate/index.js +10 -0
- package/src/bop-sdk/interface/service/offline/validate/transaction.js +51 -0
- package/src/bop-sdk/interface/service/transaction.ts +731 -0
- package/src/bop-sdk/interface/signer.ts +46 -0
- package/src/bop-sdk/interface/test/3rd.test.ts +1571 -0
- package/src/bop-sdk/interface/test/account.test.ts +284 -0
- package/src/bop-sdk/interface/test/chain.test.ts +45 -0
- package/src/bop-sdk/interface/test/contract.test.ts +283 -0
- package/src/bop-sdk/interface/test/ledger.test.ts +166 -0
- package/src/bop-sdk/interface/test/provider.test.ts +407 -0
- package/src/bop-sdk/interface/test/signer.test.ts +105 -0
- package/src/bop-sdk/interface/test/transaction.test.ts +713 -0
- package/src/bop-sdk/proto/bop-sdk-common.proto +159 -0
- package/src/bop-sdk/proto/bop-sdk-common.ts +829 -0
- package/src/bop-sdk/proto/bop-sdk-interface.proto +581 -0
- package/src/bop-sdk/proto/bop-sdk-interface.ts +10839 -0
- package/src/bop-sdk/proto/bop-sdk-utils.proto +86 -0
- package/src/bop-sdk/proto/bop-sdk-utils.ts +1495 -0
- package/src/bop-sdk/utils/abi/abi-coder.ts +147 -0
- package/src/bop-sdk/utils/abi/address.ts +109 -0
- package/src/bop-sdk/utils/abi/bignumber.ts +403 -0
- package/src/bop-sdk/utils/abi/bytes.ts +565 -0
- package/src/bop-sdk/utils/abi/coders/abstract-coder.ts +239 -0
- package/src/bop-sdk/utils/abi/coders/address.ts +58 -0
- package/src/bop-sdk/utils/abi/coders/anonymous.ts +25 -0
- package/src/bop-sdk/utils/abi/coders/array.ts +275 -0
- package/src/bop-sdk/utils/abi/coders/boolean.ts +21 -0
- package/src/bop-sdk/utils/abi/coders/bytes.ts +36 -0
- package/src/bop-sdk/utils/abi/coders/fixed-bytes.ts +35 -0
- package/src/bop-sdk/utils/abi/coders/null.ts +25 -0
- package/src/bop-sdk/utils/abi/coders/number.ts +56 -0
- package/src/bop-sdk/utils/abi/coders/string.ts +24 -0
- package/src/bop-sdk/utils/abi/coders/tuple.ts +73 -0
- package/src/bop-sdk/utils/abi/constants/addresses.ts +1 -0
- package/src/bop-sdk/utils/abi/constants/bignumbers.ts +30 -0
- package/src/bop-sdk/utils/abi/constants/hashes.ts +2 -0
- package/src/bop-sdk/utils/abi/constants/index.ts +15 -0
- package/src/bop-sdk/utils/abi/constants/strings.ts +2 -0
- package/src/bop-sdk/utils/abi/fragments.ts +1243 -0
- package/src/bop-sdk/utils/abi/id.ts +6 -0
- package/src/bop-sdk/utils/abi/index.ts +46 -0
- package/src/bop-sdk/utils/abi/interface.ts +921 -0
- package/src/bop-sdk/utils/abi/keccak256.ts +9 -0
- package/src/bop-sdk/utils/abi/properties.ts +172 -0
- package/src/bop-sdk/utils/abi/strings/bytes32.ts +40 -0
- package/src/bop-sdk/utils/abi/strings/idna.ts +258 -0
- package/src/bop-sdk/utils/abi/strings/index.ts +28 -0
- package/src/bop-sdk/utils/abi/strings/utf8.ts +373 -0
- package/src/bop-sdk/utils/encryption-address.ts +501 -0
- package/src/bop-sdk/utils/encryption-crypto.ts +427 -0
- package/src/bop-sdk/utils/encryption-mnemonics.ts +120 -0
- package/src/bop-sdk/utils/index.ts +27 -0
- package/src/bop-sdk/utils/logger.ts +480 -0
- package/src/index.ts +35 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DropTxMessage,
|
|
3
|
+
LedgerHeaderMessage,
|
|
4
|
+
MessageType,
|
|
5
|
+
SubscribeRequest,
|
|
6
|
+
TransactionEnvStoreMessage,
|
|
7
|
+
messageTypeFromJSON,
|
|
8
|
+
} from "../bop-proto/bop-ws";
|
|
9
|
+
|
|
10
|
+
import ReconnectingWebSocket from "reconnecting-websocket";
|
|
11
|
+
import WS from "ws";
|
|
12
|
+
import crypto from "crypto";
|
|
13
|
+
|
|
14
|
+
export class WsConfig {
|
|
15
|
+
constructor(
|
|
16
|
+
public readonly url: string,
|
|
17
|
+
public readonly heartBeatInterval: number = 5000, // 默认值为5000毫秒(5秒)
|
|
18
|
+
) {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface Callback {
|
|
22
|
+
(data: any): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 排除心跳和错误消息的 MessageType
|
|
26
|
+
type SubscribableMessageType = Exclude<
|
|
27
|
+
MessageType,
|
|
28
|
+
MessageType.HEARTBEAT | MessageType.ERROR
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
// 订阅信息结构
|
|
32
|
+
interface Subscription {
|
|
33
|
+
id: string;
|
|
34
|
+
callback: Callback;
|
|
35
|
+
accounts?: string[]; // 合并 message 和 sourceAccounts 为 accounts
|
|
36
|
+
type: SubscribableMessageType;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class BopWsInterface {
|
|
40
|
+
private readonly interval: number;
|
|
41
|
+
private heartbeatInterval?: NodeJS.Timeout; // 用于存储心跳定时器的ID
|
|
42
|
+
private wsUrl: string;
|
|
43
|
+
|
|
44
|
+
private socket: ReconnectingWebSocket | null;
|
|
45
|
+
|
|
46
|
+
// 调整 subscriptions 结构为 Map,key 为 id
|
|
47
|
+
private subscriptions: Map<string, Subscription> = new Map();
|
|
48
|
+
|
|
49
|
+
private readyPromise: Promise<void>;
|
|
50
|
+
private readyResolve: () => void;
|
|
51
|
+
|
|
52
|
+
private reconnectAttempts = 0;
|
|
53
|
+
private maxReconnectAttempts = 5;
|
|
54
|
+
private reconnectWaitTime = 5000; // 重连等待时间,单位:毫秒
|
|
55
|
+
private connectionTimeout = 10000; // 连接超时时间,单位:毫秒
|
|
56
|
+
|
|
57
|
+
// 新增标志位,用于区分主动断开和异常断开
|
|
58
|
+
private isManuallyDisconnected = false;
|
|
59
|
+
|
|
60
|
+
constructor(url: string, interval: number) {
|
|
61
|
+
this.wsUrl = url;
|
|
62
|
+
this.interval = interval;
|
|
63
|
+
|
|
64
|
+
this.resetReadyState();
|
|
65
|
+
|
|
66
|
+
this.createWebSocket();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public async waitForReady(): Promise<void> {
|
|
70
|
+
await this.readyPromise;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private setupEventListeners(): void {
|
|
74
|
+
if (this.socket) {
|
|
75
|
+
this.socket.addEventListener("open", (event: Event) => {
|
|
76
|
+
console.log("WebSocket connection opened");
|
|
77
|
+
this.readyResolve(); // 解决 Promise
|
|
78
|
+
this.reconnectAttempts = 0; // 重置重连次数
|
|
79
|
+
this.startHeartbeat();
|
|
80
|
+
this.resubscribeAfterReconnect(); // 重连成功后重新订阅
|
|
81
|
+
this.isManuallyDisconnected = false; // 连接成功后重置标志位
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
this.socket.addEventListener("message", (event: MessageEvent) => {
|
|
85
|
+
try {
|
|
86
|
+
const data = JSON.parse(event.data) as {
|
|
87
|
+
type: MessageType;
|
|
88
|
+
message: any;
|
|
89
|
+
};
|
|
90
|
+
// console.log(
|
|
91
|
+
// "ws: type:",
|
|
92
|
+
// data.type,
|
|
93
|
+
// ",message:",
|
|
94
|
+
// JSON.stringify(data.message),
|
|
95
|
+
// );
|
|
96
|
+
for (const [_, subscription] of this.subscriptions) {
|
|
97
|
+
if (subscription.type === data.type) {
|
|
98
|
+
if (
|
|
99
|
+
MessageType.BLOCK_HEADER !== data.type &&
|
|
100
|
+
subscription.accounts &&
|
|
101
|
+
subscription.accounts.length !== 0
|
|
102
|
+
) {
|
|
103
|
+
// 解析交易结构,这里假设交易结构中有一个字段叫 sourceAccount 表示源账户地址
|
|
104
|
+
let sourceAccount = "";
|
|
105
|
+
if (
|
|
106
|
+
data.type === MessageType.BID_TRANSACTION ||
|
|
107
|
+
data.type === MessageType.TLOG
|
|
108
|
+
) {
|
|
109
|
+
sourceAccount =
|
|
110
|
+
data.message.transaction_env.transaction.source_address;
|
|
111
|
+
}
|
|
112
|
+
if (data.type === MessageType.DISCARD_TRANSACTION) {
|
|
113
|
+
const tx = JSON.parse(data.message.tx);
|
|
114
|
+
sourceAccount = tx.transaction.source_address;
|
|
115
|
+
}
|
|
116
|
+
//console.log("ws type:", data.type, "source:", sourceAccount);
|
|
117
|
+
|
|
118
|
+
if (subscription.accounts.includes(sourceAccount)) {
|
|
119
|
+
// console.log(
|
|
120
|
+
// "ws include source_address:",
|
|
121
|
+
// sourceAccount,
|
|
122
|
+
// "id:",
|
|
123
|
+
// subscription.id,
|
|
124
|
+
// );
|
|
125
|
+
subscription.callback(data.message);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
//不包含accounts的订阅全部返回
|
|
129
|
+
subscription.callback(data.message);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error("Error parsing WebSocket message:", error);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
this.socket.addEventListener("close", (event: CloseEvent) => {
|
|
139
|
+
console.log("WebSocket connection closed");
|
|
140
|
+
this.stopHeartbeat();
|
|
141
|
+
if (!this.isManuallyDisconnected) {
|
|
142
|
+
this.handleConnectionClose();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
this.socket.addEventListener("error", (event: ErrorEvent) => {
|
|
147
|
+
console.error("WebSocket error:", event.message);
|
|
148
|
+
if (!this.isManuallyDisconnected) {
|
|
149
|
+
this.handleConnectionClose();
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private handleConnectionClose() {
|
|
156
|
+
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
157
|
+
console.log(
|
|
158
|
+
`Attempting to reconnect (attempt ${this.reconnectAttempts + 1}) in ${this.reconnectWaitTime / 1000} seconds...`,
|
|
159
|
+
);
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
this.reconnectAttempts++;
|
|
162
|
+
this.resetReadyState();
|
|
163
|
+
this.closeWebSocket();
|
|
164
|
+
this.createWebSocket();
|
|
165
|
+
}, this.reconnectWaitTime);
|
|
166
|
+
} else {
|
|
167
|
+
console.log("Max reconnect attempts reached. Exiting.");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 开始发送心跳消息
|
|
172
|
+
private startHeartbeat(): void {
|
|
173
|
+
console.log("start heart beat");
|
|
174
|
+
if (this.heartbeatInterval === undefined) {
|
|
175
|
+
this.heartbeatInterval = setInterval(() => {
|
|
176
|
+
this.sendHeartbeat();
|
|
177
|
+
}, this.interval);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 停止发送心跳消息
|
|
182
|
+
private stopHeartbeat(): void {
|
|
183
|
+
if (this.heartbeatInterval !== undefined) {
|
|
184
|
+
clearInterval(this.heartbeatInterval);
|
|
185
|
+
this.heartbeatInterval = undefined;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private sendHeartbeat(): void {
|
|
190
|
+
if (this.socket && this.socket.readyState === ReconnectingWebSocket.OPEN) {
|
|
191
|
+
this.socket.send(
|
|
192
|
+
JSON.stringify({ type: MessageType.HEARTBEAT, message: "ping" }),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private startsWithDidBid(identifier: string): boolean {
|
|
198
|
+
const regex = /^(did:bid:ef|did:bid:zf)/;
|
|
199
|
+
return regex.test(identifier);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private async sendMessage(
|
|
203
|
+
type: MessageType,
|
|
204
|
+
accounts?: string[],
|
|
205
|
+
): Promise<void> {
|
|
206
|
+
await this.waitForReady(); // 等待连接就绪
|
|
207
|
+
// 如果连接仍然不是开放的(尽管我们刚刚尝试连接),则抛出异常
|
|
208
|
+
if (!this.socket || this.socket.readyState !== ReconnectingWebSocket.OPEN) {
|
|
209
|
+
throw new Error("WebSocket is not connected");
|
|
210
|
+
}
|
|
211
|
+
const payload = { type, message: accounts || [] };
|
|
212
|
+
this.socket.send(JSON.stringify(payload));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public async subscribe(
|
|
216
|
+
type: SubscribableMessageType,
|
|
217
|
+
callback: Callback,
|
|
218
|
+
accounts?: string[], // 合并参数
|
|
219
|
+
): Promise<string> {
|
|
220
|
+
await this.waitForReady(); // 等待连接就绪
|
|
221
|
+
const subscriptionId = this.generateSubscriptionId();
|
|
222
|
+
const subscription: Subscription = {
|
|
223
|
+
id: subscriptionId,
|
|
224
|
+
callback,
|
|
225
|
+
accounts,
|
|
226
|
+
type,
|
|
227
|
+
};
|
|
228
|
+
if (accounts && accounts.length !== 0) {
|
|
229
|
+
for (const account of accounts) {
|
|
230
|
+
if (!this.startsWithDidBid(account)) {
|
|
231
|
+
return "-1";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
this.subscriptions.set(subscriptionId, subscription);
|
|
237
|
+
await this.sendMessage(type, accounts);
|
|
238
|
+
return subscriptionId;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
public async unsubscribe(
|
|
242
|
+
type: SubscribableMessageType,
|
|
243
|
+
subscriptionId: string,
|
|
244
|
+
): Promise<void> {
|
|
245
|
+
await this.waitForReady(); // 等待连接就绪
|
|
246
|
+
if (this.subscriptions.has(subscriptionId)) {
|
|
247
|
+
const subscription = this.subscriptions.get(subscriptionId)!;
|
|
248
|
+
if (subscription.type === type) {
|
|
249
|
+
this.subscriptions.delete(subscriptionId);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public async unsubscribeAll(): Promise<void> {
|
|
255
|
+
console.log("unsubscribeAll");
|
|
256
|
+
await this.waitForReady(); // 等待连接就绪
|
|
257
|
+
this.subscriptions.clear();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public async disconnect(): Promise<void> {
|
|
261
|
+
this.isManuallyDisconnected = true; // 标记为主动断开
|
|
262
|
+
await this.unsubscribeAll(); // 客户端主动退出前,取消所有订阅
|
|
263
|
+
this.closeWebSocket();
|
|
264
|
+
this.socket = null;
|
|
265
|
+
// 清除心跳定时器
|
|
266
|
+
this.stopHeartbeat();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private generateSubscriptionId(): string {
|
|
270
|
+
// 获取当前时间戳
|
|
271
|
+
const timestamp = Date.now().toString();
|
|
272
|
+
// 生成随机数
|
|
273
|
+
const randomValue = Math.random().toString();
|
|
274
|
+
// 组合时间戳和随机数
|
|
275
|
+
const input = timestamp + randomValue;
|
|
276
|
+
// 创建 sha256 哈希对象
|
|
277
|
+
const hash = crypto.createHash("sha256");
|
|
278
|
+
// 更新哈希对象的输入
|
|
279
|
+
hash.update(input);
|
|
280
|
+
// 计算哈希值并转换为十六进制字符串
|
|
281
|
+
const hashValue = hash.digest("hex");
|
|
282
|
+
// 截取前 9 位作为订阅 ID
|
|
283
|
+
return hashValue.substr(0, 9);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private resetReadyState() {
|
|
287
|
+
this.readyPromise = new Promise((resolve) => {
|
|
288
|
+
this.readyResolve = resolve;
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private createWebSocket() {
|
|
293
|
+
const options = {
|
|
294
|
+
WebSocket: WS, // custom WebSocket constructor
|
|
295
|
+
connectionTimeout: this.connectionTimeout,
|
|
296
|
+
maxRetries: 10,
|
|
297
|
+
};
|
|
298
|
+
this.socket = new ReconnectingWebSocket(this.wsUrl, [], options);
|
|
299
|
+
this.setupEventListeners();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private closeWebSocket() {
|
|
303
|
+
if (this.socket) {
|
|
304
|
+
this.socket.close();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private async resubscribeAfterReconnect() {
|
|
309
|
+
console.log("resubscribeAfterReconnect", this.subscriptions.size);
|
|
310
|
+
for (const [_, subscription] of this.subscriptions) {
|
|
311
|
+
console.log("resubscribeAfterReconnect ID:", subscription.id);
|
|
312
|
+
await this.sendMessage(subscription.type, subscription.accounts);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { WsConfig } from "..";
|
|
2
|
+
import { BopWsInterface } from "..";
|
|
3
|
+
import {
|
|
4
|
+
DropTxMessage,
|
|
5
|
+
LedgerHeaderMessage,
|
|
6
|
+
TransactionEnvStoreMessage,
|
|
7
|
+
MessageType,
|
|
8
|
+
} from "../../bop-proto/bop-ws";
|
|
9
|
+
|
|
10
|
+
const config = new WsConfig("https://bif-mainnet.bitfactory.cn/bif/subscribe");
|
|
11
|
+
const bopWs = new BopWsInterface(config.url, config.heartBeatInterval);
|
|
12
|
+
|
|
13
|
+
async function blockHeader() {
|
|
14
|
+
try {
|
|
15
|
+
const subscriptionBlockHeaderId = await bopWs.subscribe(
|
|
16
|
+
MessageType.BLOCK_HEADER,
|
|
17
|
+
(data) => {
|
|
18
|
+
let message: LedgerHeaderMessage = {};
|
|
19
|
+
message = LedgerHeaderMessage.fromJSON(data);
|
|
20
|
+
console.log("dealBlockHeader ing...", message);
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
console.log("Subscription BlockHeader ID:", subscriptionBlockHeaderId);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("An error occurred:", error);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function bidTransaction() {
|
|
30
|
+
try {
|
|
31
|
+
const subscriptionBidTransactionId = await bopWs.subscribe(
|
|
32
|
+
MessageType.BID_TRANSACTION,
|
|
33
|
+
(data) => {
|
|
34
|
+
let val = TransactionEnvStoreMessage.fromJSON(data);
|
|
35
|
+
console.log("dealtransaction ing...", val);
|
|
36
|
+
},
|
|
37
|
+
["did:bid:zfVHJnop875UMPmskam4JC4kLW4tAaDK"],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
console.log("Subscription transaction ID:", subscriptionBidTransactionId);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error("An error occurred:", error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function discardTransaction() {
|
|
47
|
+
try {
|
|
48
|
+
const subscriptionDiscardTransactionId = await bopWs.subscribe(
|
|
49
|
+
MessageType.DISCARD_TRANSACTION,
|
|
50
|
+
(data) => {
|
|
51
|
+
let val = DropTxMessage.fromJSON(data);
|
|
52
|
+
console.log("deal discardTransaction ing...", val);
|
|
53
|
+
},
|
|
54
|
+
["did:bid:zfVHJnop875UMPmskam4JC4kLW4tAaDK"],
|
|
55
|
+
);
|
|
56
|
+
console.log(
|
|
57
|
+
"Subscription transaction ID:",
|
|
58
|
+
subscriptionDiscardTransactionId,
|
|
59
|
+
);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error("An error occurred:", error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function tlogTransaction() {
|
|
66
|
+
try {
|
|
67
|
+
const subscriptionTlogTransactionId = await bopWs.subscribe(
|
|
68
|
+
MessageType.TLOG,
|
|
69
|
+
(data) => {
|
|
70
|
+
let val = TransactionEnvStoreMessage.fromJSON(data);
|
|
71
|
+
console.log("deal tlogTransaction ing...", val);
|
|
72
|
+
},
|
|
73
|
+
["did:bid:efhj9cgStGJckhLwHZefYS9Yje38NVuP"],
|
|
74
|
+
);
|
|
75
|
+
console.log("Subscription transaction ID:", subscriptionTlogTransactionId);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error("An error occurred:", error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function errorBidCheck() {
|
|
82
|
+
try {
|
|
83
|
+
const subscriptionTlogTransactionId = await bopWs.subscribe(
|
|
84
|
+
MessageType.TLOG,
|
|
85
|
+
(data) => {
|
|
86
|
+
let val = TransactionEnvStoreMessage.fromJSON(data);
|
|
87
|
+
console.log("deal tlogTransaction ing...", val);
|
|
88
|
+
},
|
|
89
|
+
["xxx"],
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (subscriptionTlogTransactionId === "-1") {
|
|
93
|
+
console.log("subscription bid address error");
|
|
94
|
+
await bopWs.disconnect();
|
|
95
|
+
} else {
|
|
96
|
+
console.log(
|
|
97
|
+
"Subscription transaction ID:",
|
|
98
|
+
subscriptionTlogTransactionId,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error("An error occurred:", error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 调用 main 函数
|
|
107
|
+
errorBidCheck();
|
package/src/bop/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BopInterface, Config } from "./bop-base";
|
|
2
|
+
import * as bopprotocol from "./bop-proto/bop";
|
|
3
|
+
import { BopWsInterface, WsConfig } from "./bop-ws";
|
|
4
|
+
import * as bopwsprotocol from "./bop-proto/bop-ws";
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
BopInterface,
|
|
8
|
+
Config,
|
|
9
|
+
bopprotocol,
|
|
10
|
+
//ws
|
|
11
|
+
BopWsInterface,
|
|
12
|
+
WsConfig,
|
|
13
|
+
bopwsprotocol,
|
|
14
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SignerByBop } from "./interface/signer";
|
|
2
|
+
import { ProviderByBop } from "./interface/provider";
|
|
3
|
+
import { WsProviderByBop } from "./interface/provider-ws";
|
|
4
|
+
import { defaultUtils, Interface } from "./utils";
|
|
5
|
+
import * as sdkProtocolCommon from "./proto/bop-sdk-common";
|
|
6
|
+
import * as sdkProtocolInterface from "./proto/bop-sdk-interface";
|
|
7
|
+
import * as sdkProtocolUtils from "./proto/bop-sdk-utils";
|
|
8
|
+
|
|
9
|
+
const sdkprotocol = {
|
|
10
|
+
common: sdkProtocolCommon,
|
|
11
|
+
interface: sdkProtocolInterface,
|
|
12
|
+
utils: sdkProtocolUtils,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
SignerByBop,
|
|
17
|
+
ProviderByBop,
|
|
18
|
+
defaultUtils,
|
|
19
|
+
Interface,
|
|
20
|
+
sdkprotocol,
|
|
21
|
+
WsProviderByBop,
|
|
22
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GetAccountResponse,
|
|
3
|
+
GetAccountMetadataResponse,
|
|
4
|
+
GetAccountIncreaseNonceResponse,
|
|
5
|
+
GetAccountBalanceResponse,
|
|
6
|
+
GetAccountPrivResponse,
|
|
7
|
+
} from "bop-sdk/proto/bop-sdk-interface";
|
|
8
|
+
|
|
9
|
+
export abstract class account {
|
|
10
|
+
abstract getAccount(address: string): Promise<GetAccountResponse>;
|
|
11
|
+
abstract getAccountMetadata(
|
|
12
|
+
address: string,
|
|
13
|
+
seq?: number | "latest",
|
|
14
|
+
key?: string,
|
|
15
|
+
): Promise<GetAccountMetadataResponse>;
|
|
16
|
+
abstract getAccountIncreaseNonce(
|
|
17
|
+
address: string,
|
|
18
|
+
): Promise<GetAccountIncreaseNonceResponse>;
|
|
19
|
+
abstract getAccountBalance(
|
|
20
|
+
address: string,
|
|
21
|
+
): Promise<GetAccountBalanceResponse>;
|
|
22
|
+
abstract getAccountPriv(address: string): Promise<GetAccountPrivResponse>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CheckContractAccountResponse,
|
|
3
|
+
GetContractInfoResponse,
|
|
4
|
+
CallContractRequest,
|
|
5
|
+
CallContractResponse,
|
|
6
|
+
} from "bop-sdk/proto/bop-sdk-interface";
|
|
7
|
+
|
|
8
|
+
export abstract class contract {
|
|
9
|
+
abstract checkContractAccount(
|
|
10
|
+
address: string,
|
|
11
|
+
): Promise<CheckContractAccountResponse>;
|
|
12
|
+
abstract getContractInfo(address: string): Promise<GetContractInfoResponse>;
|
|
13
|
+
abstract callContract(
|
|
14
|
+
transaction: CallContractRequest,
|
|
15
|
+
): Promise<CallContractResponse>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LedgerResponse,
|
|
3
|
+
LedgerNumberResponse,
|
|
4
|
+
LedgerLeaderResponse,
|
|
5
|
+
LedgerValidatorsResponse,
|
|
6
|
+
LedgerTxHashesResponse,
|
|
7
|
+
} from "bop-sdk/proto/bop-sdk-interface";
|
|
8
|
+
|
|
9
|
+
export abstract class ledger {
|
|
10
|
+
abstract getLedger(seq?: number): Promise<LedgerResponse>;
|
|
11
|
+
abstract getLedgerNumber(): Promise<LedgerNumberResponse>;
|
|
12
|
+
abstract getLedgerLeader(seq?: number): Promise<LedgerLeaderResponse>;
|
|
13
|
+
abstract getLedgerValidators(seq?: number): Promise<LedgerValidatorsResponse>;
|
|
14
|
+
abstract getLedgerTxHashes(seq?: number): Promise<LedgerTxHashesResponse>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { account as Account } from "./abstract-account";
|
|
2
|
+
import { chain as Chain } from "./abstract-chain";
|
|
3
|
+
import { contract as Contract } from "./abstract-contract";
|
|
4
|
+
import { ledger as Ledger } from "./abstract-ledger";
|
|
5
|
+
import { transaction as Transaction } from "./abstract-transaction";
|
|
6
|
+
|
|
7
|
+
export abstract class Provider {
|
|
8
|
+
public chain: Chain;
|
|
9
|
+
public ledger: Ledger;
|
|
10
|
+
public account: Account;
|
|
11
|
+
public transaction: Transaction;
|
|
12
|
+
public contract: Contract;
|
|
13
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CallContractRequest,
|
|
3
|
+
CallContractResponse,
|
|
4
|
+
GetAccountBalanceResponse,
|
|
5
|
+
GetAccountIncreaseNonceResponse,
|
|
6
|
+
SignerSignResponse,
|
|
7
|
+
TestTransactionRequest,
|
|
8
|
+
TestTransactionResponse,
|
|
9
|
+
LedgerNumberResponse,
|
|
10
|
+
GetAccountResponse,
|
|
11
|
+
} from "../../../bop-sdk/proto/bop-sdk-interface";
|
|
12
|
+
import { Provider } from "./abstract-provider";
|
|
13
|
+
import { SdkStatusCode } from "../../../bop-sdk/proto/bop-sdk-common";
|
|
14
|
+
|
|
15
|
+
function defineReadOnly<T, K extends keyof T>(
|
|
16
|
+
object: T,
|
|
17
|
+
name: K,
|
|
18
|
+
value: T[K],
|
|
19
|
+
): void {
|
|
20
|
+
Object.defineProperty(object, name, {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
value: value,
|
|
23
|
+
writable: false,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export abstract class Signer {
|
|
28
|
+
public provider?: Provider;
|
|
29
|
+
|
|
30
|
+
readonly _isSigner: boolean;
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
defineReadOnly(this, "_isSigner", true);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_checkProvider(operation?: string): string {
|
|
37
|
+
if (!this.provider) {
|
|
38
|
+
if (operation === undefined) return "unconnected provider";
|
|
39
|
+
else return operation + " unconnected provider";
|
|
40
|
+
}
|
|
41
|
+
return "ok";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
abstract connect(provider: Provider): Signer;
|
|
45
|
+
|
|
46
|
+
static isSigner(value: any): value is Signer {
|
|
47
|
+
return !!(value && value._isSigner);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
abstract getAddress(): string;
|
|
51
|
+
|
|
52
|
+
abstract signTransaction(message: string): Promise<SignerSignResponse>;
|
|
53
|
+
|
|
54
|
+
async getAccount(address?: string): Promise<GetAccountResponse> {
|
|
55
|
+
if (this._checkProvider("getAccount") !== "ok") {
|
|
56
|
+
const response: GetAccountResponse = {
|
|
57
|
+
errorCode: SdkStatusCode.UNCONNECTED_PROVIDER,
|
|
58
|
+
errorDesc: this._checkProvider("getAccount"),
|
|
59
|
+
};
|
|
60
|
+
return response;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (address === undefined)
|
|
64
|
+
return (await this.provider.account.getAccount(
|
|
65
|
+
this.getAddress(),
|
|
66
|
+
)) as GetAccountResponse;
|
|
67
|
+
else
|
|
68
|
+
return (await this.provider.account.getAccount(
|
|
69
|
+
address,
|
|
70
|
+
)) as GetAccountResponse;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async getLedgerNumber(): Promise<LedgerNumberResponse> {
|
|
74
|
+
if (this._checkProvider("getLedgerNumber") !== "ok") {
|
|
75
|
+
const response: LedgerNumberResponse = {
|
|
76
|
+
errorCode: SdkStatusCode.UNCONNECTED_PROVIDER,
|
|
77
|
+
errorDesc: this._checkProvider("getLedgerNumber"),
|
|
78
|
+
};
|
|
79
|
+
return response;
|
|
80
|
+
}
|
|
81
|
+
return (await this.provider.ledger.getLedgerNumber()) as LedgerNumberResponse;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async getBalance(): Promise<GetAccountBalanceResponse> {
|
|
85
|
+
if (this._checkProvider("getBalance") !== "ok") {
|
|
86
|
+
const response: GetAccountBalanceResponse = {
|
|
87
|
+
errorCode: SdkStatusCode.UNCONNECTED_PROVIDER,
|
|
88
|
+
errorDesc: this._checkProvider("getBalance"),
|
|
89
|
+
};
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
return (await this.provider.account.getAccountBalance(
|
|
93
|
+
this.getAddress(),
|
|
94
|
+
)) as GetAccountBalanceResponse;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async getIncreaseNonce(): Promise<GetAccountIncreaseNonceResponse> {
|
|
98
|
+
if (this._checkProvider("getIncreaseNonce") !== "ok") {
|
|
99
|
+
const response: GetAccountIncreaseNonceResponse = {
|
|
100
|
+
errorCode: SdkStatusCode.UNCONNECTED_PROVIDER,
|
|
101
|
+
errorDesc: this._checkProvider("getIncreaseNonce"),
|
|
102
|
+
};
|
|
103
|
+
return response;
|
|
104
|
+
}
|
|
105
|
+
return (await this.provider.account.getAccountIncreaseNonce(
|
|
106
|
+
this.getAddress(),
|
|
107
|
+
)) as GetAccountIncreaseNonceResponse;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async callContract(
|
|
111
|
+
sourceAddress: string,
|
|
112
|
+
input: string,
|
|
113
|
+
): Promise<CallContractResponse> {
|
|
114
|
+
if (this._checkProvider("callContract") !== "ok") {
|
|
115
|
+
const response: CallContractResponse = {
|
|
116
|
+
errorCode: SdkStatusCode.UNCONNECTED_PROVIDER,
|
|
117
|
+
errorDesc: this._checkProvider("callContract"),
|
|
118
|
+
};
|
|
119
|
+
return response;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const transaction: CallContractRequest = {
|
|
123
|
+
contractAddress: sourceAddress,
|
|
124
|
+
input: input,
|
|
125
|
+
gasPrice: 1,
|
|
126
|
+
sourceAddress: this.getAddress(),
|
|
127
|
+
optType: 2, //query
|
|
128
|
+
};
|
|
129
|
+
return (await this.provider.contract.callContract(
|
|
130
|
+
transaction,
|
|
131
|
+
)) as CallContractResponse;
|
|
132
|
+
}
|
|
133
|
+
}
|