koilib 5.5.3 → 5.5.4
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/package.json +3 -2
- package/src/Contract.ts +614 -0
- package/src/Provider.ts +512 -0
- package/src/Serializer.ts +366 -0
- package/src/Signer.ts +827 -0
- package/src/Transaction.ts +241 -0
- package/src/index.ts +9 -0
- package/src/index2.ts +17 -0
- package/src/indexUtils.ts +2 -0
- package/src/interface.ts +767 -0
- package/src/jsonDescriptors/chain-proto.json +726 -0
- package/src/jsonDescriptors/pow-proto.json +68 -0
- package/src/jsonDescriptors/token-proto.json +255 -0
- package/src/jsonDescriptors/value-proto.json +161 -0
- package/src/protoModules/protocol-proto.js +8138 -0
- package/src/protoModules/value-proto.js +1736 -0
- package/src/utils.ts +533 -0
- package/src/utilsNode.ts +378 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
2
|
+
import { Root, Type, INamespace, parse } from "protobufjs";
|
|
3
|
+
import * as koinosPbToProto from "@roamin/koinos-pb-to-proto";
|
|
4
|
+
import { TypeField } from "./interface";
|
|
5
|
+
import {
|
|
6
|
+
btypeDecodeValue,
|
|
7
|
+
btypeEncodeValue,
|
|
8
|
+
decodeBase64url,
|
|
9
|
+
decodeBase64,
|
|
10
|
+
} from "./utils";
|
|
11
|
+
|
|
12
|
+
const OP_BYTES_1 = "(btype)";
|
|
13
|
+
const OP_BYTES_2 = "(koinos.btype)";
|
|
14
|
+
|
|
15
|
+
const nativeTypes = [
|
|
16
|
+
"double",
|
|
17
|
+
"float",
|
|
18
|
+
"int32",
|
|
19
|
+
"int64",
|
|
20
|
+
"uint32",
|
|
21
|
+
"uint64",
|
|
22
|
+
"sint32",
|
|
23
|
+
"sint64",
|
|
24
|
+
"fixed32",
|
|
25
|
+
"fixed64",
|
|
26
|
+
"sfixed32",
|
|
27
|
+
"sfixed64",
|
|
28
|
+
"bool",
|
|
29
|
+
"string",
|
|
30
|
+
"bytes",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The serializer class serialize and deserialize data using
|
|
35
|
+
* protocol buffers. It accepts the descriptor in JSON or binary format
|
|
36
|
+
*
|
|
37
|
+
* NOTE: This class uses the [protobufjs](https://www.npmjs.com/package/protobufjs)
|
|
38
|
+
* library internally, which uses reflection (use of _eval_
|
|
39
|
+
* and _new Function_) for the construction of the types.
|
|
40
|
+
* This could cause issues in environments where _eval_ is not
|
|
41
|
+
* allowed, like in browser extensions. In such cases, this class
|
|
42
|
+
* must be confined in a [sandbox environment](https://developer.chrome.com/docs/apps/app_external/#sandboxing)
|
|
43
|
+
* where _eval_ is allowed. This is the principal reason of
|
|
44
|
+
* having the serializer in a separate class.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* // using descriptor JSON
|
|
50
|
+
* const descriptorJson = {
|
|
51
|
+
* nested: {
|
|
52
|
+
* awesomepackage: {
|
|
53
|
+
* nested: {
|
|
54
|
+
* AwesomeMessage: {
|
|
55
|
+
* fields: {
|
|
56
|
+
* awesome_field: {
|
|
57
|
+
* type: "string",
|
|
58
|
+
* id: 1,
|
|
59
|
+
* },
|
|
60
|
+
* },
|
|
61
|
+
* },
|
|
62
|
+
* },
|
|
63
|
+
* },
|
|
64
|
+
* },
|
|
65
|
+
* };
|
|
66
|
+
* const serializer1 = new Serializer(descriptorJson);
|
|
67
|
+
* const message1 = await serializer1.deserialize(
|
|
68
|
+
* "CgZrb2lub3M=",
|
|
69
|
+
* "AwesomeMessage"
|
|
70
|
+
* );
|
|
71
|
+
* console.log(message1);
|
|
72
|
+
* // { awesome_field: 'koinos' }
|
|
73
|
+
*
|
|
74
|
+
* // using descriptor binary
|
|
75
|
+
* const descriptorBinary =
|
|
76
|
+
* "Cl4KDWF3ZXNvbWUucHJvdG8SDmF3ZXNvbWVwYWN" +
|
|
77
|
+
* "rYWdlIjUKDkF3ZXNvbWVNZXNzYWdlEiMKDWF3ZX" +
|
|
78
|
+
* "NvbWVfZmllbGQYASABKAlSDGF3ZXNvbWVGaWVsZ" +
|
|
79
|
+
* "GIGcHJvdG8z";
|
|
80
|
+
* const serializer2 = new Serializer(descriptorBinary);
|
|
81
|
+
* const message2 = await serializer2.deserialize(
|
|
82
|
+
* "CgZrb2lub3M=",
|
|
83
|
+
* "AwesomeMessage"
|
|
84
|
+
* );
|
|
85
|
+
* console.log(message2);
|
|
86
|
+
* // { awesome_field: 'koinos' }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export class Serializer {
|
|
90
|
+
/**
|
|
91
|
+
* Protobuffers descriptor in JSON format.
|
|
92
|
+
* See https://www.npmjs.com/package/protobufjs#using-json-descriptors
|
|
93
|
+
*/
|
|
94
|
+
types: INamespace | string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Protobuffer definitions
|
|
98
|
+
*/
|
|
99
|
+
root: Root;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Default type for all serializations
|
|
103
|
+
*/
|
|
104
|
+
defaultType?: Type;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Preformat bytes for base64url, base58 or hex string
|
|
108
|
+
*/
|
|
109
|
+
bytesConversion = true;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Verify checksum in addresses during serialization
|
|
113
|
+
* or deserialization
|
|
114
|
+
*/
|
|
115
|
+
verifyChecksum = {
|
|
116
|
+
serialize: true,
|
|
117
|
+
deserialize: false,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
constructor(
|
|
121
|
+
types: INamespace | string,
|
|
122
|
+
opts?: {
|
|
123
|
+
/**
|
|
124
|
+
* Default type name. Use this option when you
|
|
125
|
+
* always want to serialize/deserialize the same type
|
|
126
|
+
*/
|
|
127
|
+
defaultTypeName?: string;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Bytes conversion. Option to preformat bytes
|
|
131
|
+
* when "(koinos_bytes_type)" is defined in the type
|
|
132
|
+
* definitions. By default it is true.
|
|
133
|
+
*/
|
|
134
|
+
bytesConversion?: boolean;
|
|
135
|
+
}
|
|
136
|
+
) {
|
|
137
|
+
this.types = types;
|
|
138
|
+
if (typeof types === "string") {
|
|
139
|
+
const protos = koinosPbToProto.convert(decodeBase64(types) as Buffer);
|
|
140
|
+
this.root = new Root();
|
|
141
|
+
for (const proto of protos) {
|
|
142
|
+
parse(proto.definition, this.root, { keepCase: true });
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
this.root = Root.fromJSON(types);
|
|
146
|
+
}
|
|
147
|
+
if (opts?.defaultTypeName)
|
|
148
|
+
this.defaultType = this.root.lookupType(opts.defaultTypeName);
|
|
149
|
+
if (opts && typeof opts.bytesConversion !== "undefined")
|
|
150
|
+
this.bytesConversion = opts.bytesConversion;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
btypeDecode(
|
|
154
|
+
valueBtypeEncoded: Record<string, unknown> | unknown[],
|
|
155
|
+
protobufType: Type,
|
|
156
|
+
verifyChecksum: boolean
|
|
157
|
+
) {
|
|
158
|
+
const valueBtypeDecoded = {} as Record<string, unknown>;
|
|
159
|
+
Object.keys(protobufType.fields).forEach((fieldName) => {
|
|
160
|
+
// @ts-ignore
|
|
161
|
+
const { options, name, type, rule } = protobufType.fields[fieldName];
|
|
162
|
+
if (!valueBtypeEncoded[name]) return;
|
|
163
|
+
|
|
164
|
+
const typeField: TypeField = { type };
|
|
165
|
+
if (options) {
|
|
166
|
+
if (options[OP_BYTES_1])
|
|
167
|
+
typeField.btype = options[OP_BYTES_1] as string;
|
|
168
|
+
else if (options[OP_BYTES_2])
|
|
169
|
+
typeField.btype = options[OP_BYTES_2] as string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// arrays
|
|
173
|
+
if (rule === "repeated") {
|
|
174
|
+
valueBtypeDecoded[name] = (valueBtypeEncoded[name] as unknown[]).map(
|
|
175
|
+
(itemEncoded) => {
|
|
176
|
+
// custom objects
|
|
177
|
+
if (!nativeTypes.includes(type)) {
|
|
178
|
+
const protoBuf = this.root.lookupTypeOrEnum(type);
|
|
179
|
+
if (!protoBuf.fields) {
|
|
180
|
+
// it's an enum
|
|
181
|
+
return itemEncoded;
|
|
182
|
+
}
|
|
183
|
+
return this.btypeDecode(
|
|
184
|
+
itemEncoded as Record<string, unknown>,
|
|
185
|
+
protoBuf,
|
|
186
|
+
verifyChecksum
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
// native types
|
|
190
|
+
return btypeDecodeValue(itemEncoded, typeField, verifyChecksum);
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// custom objects
|
|
197
|
+
if (!nativeTypes.includes(type)) {
|
|
198
|
+
const protoBuf = this.root.lookupTypeOrEnum(type);
|
|
199
|
+
if (!protoBuf.fields) {
|
|
200
|
+
// it's an enum
|
|
201
|
+
valueBtypeDecoded[name] = valueBtypeEncoded[name];
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
valueBtypeDecoded[name] = this.btypeDecode(
|
|
205
|
+
valueBtypeEncoded[name] as Record<string, unknown>,
|
|
206
|
+
protoBuf,
|
|
207
|
+
verifyChecksum
|
|
208
|
+
);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// native types
|
|
213
|
+
valueBtypeDecoded[name] = btypeDecodeValue(
|
|
214
|
+
valueBtypeEncoded[name],
|
|
215
|
+
typeField,
|
|
216
|
+
verifyChecksum
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
return valueBtypeDecoded;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
btypeEncode(
|
|
224
|
+
valueBtypeDecoded: Record<string, unknown> | unknown[],
|
|
225
|
+
protobufType: Type,
|
|
226
|
+
verifyChecksum: boolean
|
|
227
|
+
) {
|
|
228
|
+
const valueBtypeEncoded = {} as Record<string, unknown>;
|
|
229
|
+
Object.keys(protobufType.fields).forEach((fieldName) => {
|
|
230
|
+
// @ts-ignore
|
|
231
|
+
const { options, name, type, rule } = protobufType.fields[fieldName];
|
|
232
|
+
if (!valueBtypeDecoded[name]) return;
|
|
233
|
+
|
|
234
|
+
const typeField: TypeField = { type };
|
|
235
|
+
if (options) {
|
|
236
|
+
if (options[OP_BYTES_1])
|
|
237
|
+
typeField.btype = options[OP_BYTES_1] as string;
|
|
238
|
+
else if (options[OP_BYTES_2])
|
|
239
|
+
typeField.btype = options[OP_BYTES_2] as string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// arrays
|
|
243
|
+
if (rule === "repeated") {
|
|
244
|
+
valueBtypeEncoded[name] = (valueBtypeDecoded[name] as unknown[]).map(
|
|
245
|
+
(itemDecoded) => {
|
|
246
|
+
// custom objects
|
|
247
|
+
if (!nativeTypes.includes(type)) {
|
|
248
|
+
const protoBuf = this.root.lookupTypeOrEnum(type);
|
|
249
|
+
if (!protoBuf.fields) {
|
|
250
|
+
// it's an enum
|
|
251
|
+
return itemDecoded;
|
|
252
|
+
}
|
|
253
|
+
return this.btypeEncode(
|
|
254
|
+
itemDecoded as Record<string, unknown>,
|
|
255
|
+
protoBuf,
|
|
256
|
+
verifyChecksum
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
// native types
|
|
260
|
+
return btypeEncodeValue(itemDecoded, typeField, verifyChecksum);
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// custom objects
|
|
267
|
+
if (!nativeTypes.includes(type)) {
|
|
268
|
+
const protoBuf = this.root.lookupTypeOrEnum(type);
|
|
269
|
+
if (!protoBuf.fields) {
|
|
270
|
+
// it's an enum
|
|
271
|
+
valueBtypeEncoded[name] = valueBtypeDecoded[name];
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
valueBtypeEncoded[name] = this.btypeEncode(
|
|
275
|
+
valueBtypeDecoded[name] as Record<string, unknown>,
|
|
276
|
+
protoBuf,
|
|
277
|
+
verifyChecksum
|
|
278
|
+
);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// native types
|
|
283
|
+
valueBtypeEncoded[name] = btypeEncodeValue(
|
|
284
|
+
valueBtypeDecoded[name],
|
|
285
|
+
typeField,
|
|
286
|
+
verifyChecksum
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return valueBtypeEncoded;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Function to encode a type using the protobuffer definitions
|
|
295
|
+
* It also prepares the bytes for special cases (base58, hex string)
|
|
296
|
+
* when bytesConversion param is true.
|
|
297
|
+
*/
|
|
298
|
+
async serialize(
|
|
299
|
+
valueDecoded: Record<string, unknown>,
|
|
300
|
+
typeName?: string,
|
|
301
|
+
opts?: { bytesConversion?: boolean; verifyChecksum?: boolean }
|
|
302
|
+
): Promise<Uint8Array> {
|
|
303
|
+
let protobufType: Type;
|
|
304
|
+
if (this.defaultType) protobufType = this.defaultType;
|
|
305
|
+
else if (!typeName) throw new Error("no typeName defined");
|
|
306
|
+
else protobufType = this.root.lookupType(typeName);
|
|
307
|
+
let object: Record<string, unknown> = {};
|
|
308
|
+
const bytesConversion =
|
|
309
|
+
opts?.bytesConversion === undefined
|
|
310
|
+
? this.bytesConversion
|
|
311
|
+
: opts.bytesConversion;
|
|
312
|
+
const verifyChecksum =
|
|
313
|
+
opts?.verifyChecksum === undefined
|
|
314
|
+
? this.verifyChecksum.serialize
|
|
315
|
+
: opts.verifyChecksum;
|
|
316
|
+
if (bytesConversion) {
|
|
317
|
+
object = this.btypeDecode(valueDecoded, protobufType, verifyChecksum);
|
|
318
|
+
} else {
|
|
319
|
+
object = valueDecoded;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const message = protobufType.create(object);
|
|
323
|
+
|
|
324
|
+
const buffer = protobufType.encode(message).finish();
|
|
325
|
+
return buffer;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Function to decode bytes using the protobuffer definitions
|
|
330
|
+
* It also encodes the bytes for special cases (base58, hex string)
|
|
331
|
+
* when bytesConversion param is true.
|
|
332
|
+
*/
|
|
333
|
+
async deserialize<T = Record<string, unknown>>(
|
|
334
|
+
valueEncoded: string | Uint8Array,
|
|
335
|
+
typeName?: string,
|
|
336
|
+
opts?: { bytesConversion?: boolean; verifyChecksum?: boolean }
|
|
337
|
+
): Promise<T> {
|
|
338
|
+
const valueBuffer =
|
|
339
|
+
typeof valueEncoded === "string"
|
|
340
|
+
? decodeBase64url(valueEncoded)
|
|
341
|
+
: valueEncoded;
|
|
342
|
+
let protobufType: Type;
|
|
343
|
+
if (this.defaultType) protobufType = this.defaultType;
|
|
344
|
+
else if (!typeName) throw new Error("no typeName defined");
|
|
345
|
+
else protobufType = this.root.lookupType(typeName);
|
|
346
|
+
const message = protobufType.decode(valueBuffer);
|
|
347
|
+
const object = protobufType.toObject(message, {
|
|
348
|
+
longs: String,
|
|
349
|
+
defaults: true,
|
|
350
|
+
});
|
|
351
|
+
const bytesConversion =
|
|
352
|
+
opts?.bytesConversion === undefined
|
|
353
|
+
? this.bytesConversion
|
|
354
|
+
: opts.bytesConversion;
|
|
355
|
+
const verifyChecksum =
|
|
356
|
+
opts?.verifyChecksum === undefined
|
|
357
|
+
? this.verifyChecksum.deserialize
|
|
358
|
+
: opts.verifyChecksum;
|
|
359
|
+
if (bytesConversion) {
|
|
360
|
+
return this.btypeEncode(object, protobufType, verifyChecksum) as T;
|
|
361
|
+
}
|
|
362
|
+
return object as T;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export default Serializer;
|