@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.
Files changed (115) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.md +112 -0
  5. package/package.json +90 -0
  6. package/src/bop/bop-base/README.md +5 -0
  7. package/src/bop/bop-base/base.ts +366 -0
  8. package/src/bop/bop-base/index.ts +83 -0
  9. package/src/bop/bop-base/permit.ts +116 -0
  10. package/src/bop/bop-base/test/base.test.ts +867 -0
  11. package/src/bop/bop-base/test/index.test.ts +69 -0
  12. package/src/bop/bop-base/test/permit.test.ts +125 -0
  13. package/src/bop/bop-base/tsconfig.json +8 -0
  14. package/src/bop/bop-proto/README.md +2 -0
  15. package/src/bop/bop-proto/bop-ws.proto +266 -0
  16. package/src/bop/bop-proto/bop-ws.ts +4447 -0
  17. package/src/bop/bop-proto/bop.proto +898 -0
  18. package/src/bop/bop-proto/bop.ts +12890 -0
  19. package/src/bop/bop-proto/tsconfig.json +8 -0
  20. package/src/bop/bop-ws/index.ts +315 -0
  21. package/src/bop/bop-ws/sample/sample.ts +107 -0
  22. package/src/bop/bop-ws/tsconfig.json +8 -0
  23. package/src/bop/index.ts +14 -0
  24. package/src/bop-sdk/index.ts +22 -0
  25. package/src/bop-sdk/interface/abstract-service/abstract-account.ts +23 -0
  26. package/src/bop-sdk/interface/abstract-service/abstract-chain.ts +9 -0
  27. package/src/bop-sdk/interface/abstract-service/abstract-contract.ts +16 -0
  28. package/src/bop-sdk/interface/abstract-service/abstract-ledger.ts +15 -0
  29. package/src/bop-sdk/interface/abstract-service/abstract-provider.ts +13 -0
  30. package/src/bop-sdk/interface/abstract-service/abstract-signer.ts +133 -0
  31. package/src/bop-sdk/interface/abstract-service/abstract-transaction.ts +86 -0
  32. package/src/bop-sdk/interface/provider-ws.ts +10 -0
  33. package/src/bop-sdk/interface/provider.ts +22 -0
  34. package/src/bop-sdk/interface/service/3rd.ts +54 -0
  35. package/src/bop-sdk/interface/service/account.ts +86 -0
  36. package/src/bop-sdk/interface/service/chain.ts +27 -0
  37. package/src/bop-sdk/interface/service/contract.ts +51 -0
  38. package/src/bop-sdk/interface/service/helper.ts +426 -0
  39. package/src/bop-sdk/interface/service/ledger.ts +75 -0
  40. package/src/bop-sdk/interface/service/offline/check/index.js +138 -0
  41. package/src/bop-sdk/interface/service/offline/common/constant.js +6 -0
  42. package/src/bop-sdk/interface/service/offline/common/snowFlakeUtils.js +192 -0
  43. package/src/bop-sdk/interface/service/offline/common/util.js +511 -0
  44. package/src/bop-sdk/interface/service/offline/exception/customErrors.js +29 -0
  45. package/src/bop-sdk/interface/service/offline/exception/errors.js +90 -0
  46. package/src/bop-sdk/interface/service/offline/exception/index.js +5 -0
  47. package/src/bop-sdk/interface/service/offline/operation/accountCreateOperation.js +28 -0
  48. package/src/bop-sdk/interface/service/offline/operation/accountSetMetadataOperation.js +44 -0
  49. package/src/bop-sdk/interface/service/offline/operation/accountSetPrivilegeOperation.js +49 -0
  50. package/src/bop-sdk/interface/service/offline/operation/contractCreateOperation.js +43 -0
  51. package/src/bop-sdk/interface/service/offline/operation/contractInvokeOperation.js +42 -0
  52. package/src/bop-sdk/interface/service/offline/operation/contractInvokeRequestOperation.js +69 -0
  53. package/src/bop-sdk/interface/service/offline/operation/gasSendOperation.js +29 -0
  54. package/src/bop-sdk/interface/service/offline/operation/gasSendRequestOperation.js +61 -0
  55. package/src/bop-sdk/interface/service/offline/operation/index.js +20 -0
  56. package/src/bop-sdk/interface/service/offline/proto/chain_pb.js +12079 -0
  57. package/src/bop-sdk/interface/service/offline/proto/common_pb.js +2867 -0
  58. package/src/bop-sdk/interface/service/offline/transaction/index.js +988 -0
  59. package/src/bop-sdk/interface/service/offline/transaction/operations.js +188 -0
  60. package/src/bop-sdk/interface/service/offline/validate/account.js +152 -0
  61. package/src/bop-sdk/interface/service/offline/validate/contract.js +101 -0
  62. package/src/bop-sdk/interface/service/offline/validate/index.js +10 -0
  63. package/src/bop-sdk/interface/service/offline/validate/transaction.js +51 -0
  64. package/src/bop-sdk/interface/service/transaction.ts +731 -0
  65. package/src/bop-sdk/interface/signer.ts +46 -0
  66. package/src/bop-sdk/interface/test/3rd.test.ts +1571 -0
  67. package/src/bop-sdk/interface/test/account.test.ts +284 -0
  68. package/src/bop-sdk/interface/test/chain.test.ts +45 -0
  69. package/src/bop-sdk/interface/test/contract.test.ts +283 -0
  70. package/src/bop-sdk/interface/test/ledger.test.ts +166 -0
  71. package/src/bop-sdk/interface/test/provider.test.ts +407 -0
  72. package/src/bop-sdk/interface/test/signer.test.ts +105 -0
  73. package/src/bop-sdk/interface/test/transaction.test.ts +713 -0
  74. package/src/bop-sdk/proto/bop-sdk-common.proto +159 -0
  75. package/src/bop-sdk/proto/bop-sdk-common.ts +829 -0
  76. package/src/bop-sdk/proto/bop-sdk-interface.proto +581 -0
  77. package/src/bop-sdk/proto/bop-sdk-interface.ts +10839 -0
  78. package/src/bop-sdk/proto/bop-sdk-utils.proto +86 -0
  79. package/src/bop-sdk/proto/bop-sdk-utils.ts +1495 -0
  80. package/src/bop-sdk/utils/abi/abi-coder.ts +147 -0
  81. package/src/bop-sdk/utils/abi/address.ts +109 -0
  82. package/src/bop-sdk/utils/abi/bignumber.ts +403 -0
  83. package/src/bop-sdk/utils/abi/bytes.ts +565 -0
  84. package/src/bop-sdk/utils/abi/coders/abstract-coder.ts +239 -0
  85. package/src/bop-sdk/utils/abi/coders/address.ts +58 -0
  86. package/src/bop-sdk/utils/abi/coders/anonymous.ts +25 -0
  87. package/src/bop-sdk/utils/abi/coders/array.ts +275 -0
  88. package/src/bop-sdk/utils/abi/coders/boolean.ts +21 -0
  89. package/src/bop-sdk/utils/abi/coders/bytes.ts +36 -0
  90. package/src/bop-sdk/utils/abi/coders/fixed-bytes.ts +35 -0
  91. package/src/bop-sdk/utils/abi/coders/null.ts +25 -0
  92. package/src/bop-sdk/utils/abi/coders/number.ts +56 -0
  93. package/src/bop-sdk/utils/abi/coders/string.ts +24 -0
  94. package/src/bop-sdk/utils/abi/coders/tuple.ts +73 -0
  95. package/src/bop-sdk/utils/abi/constants/addresses.ts +1 -0
  96. package/src/bop-sdk/utils/abi/constants/bignumbers.ts +30 -0
  97. package/src/bop-sdk/utils/abi/constants/hashes.ts +2 -0
  98. package/src/bop-sdk/utils/abi/constants/index.ts +15 -0
  99. package/src/bop-sdk/utils/abi/constants/strings.ts +2 -0
  100. package/src/bop-sdk/utils/abi/fragments.ts +1243 -0
  101. package/src/bop-sdk/utils/abi/id.ts +6 -0
  102. package/src/bop-sdk/utils/abi/index.ts +46 -0
  103. package/src/bop-sdk/utils/abi/interface.ts +921 -0
  104. package/src/bop-sdk/utils/abi/keccak256.ts +9 -0
  105. package/src/bop-sdk/utils/abi/properties.ts +172 -0
  106. package/src/bop-sdk/utils/abi/strings/bytes32.ts +40 -0
  107. package/src/bop-sdk/utils/abi/strings/idna.ts +258 -0
  108. package/src/bop-sdk/utils/abi/strings/index.ts +28 -0
  109. package/src/bop-sdk/utils/abi/strings/utf8.ts +373 -0
  110. package/src/bop-sdk/utils/encryption-address.ts +501 -0
  111. package/src/bop-sdk/utils/encryption-crypto.ts +427 -0
  112. package/src/bop-sdk/utils/encryption-mnemonics.ts +120 -0
  113. package/src/bop-sdk/utils/index.ts +27 -0
  114. package/src/bop-sdk/utils/logger.ts +480 -0
  115. package/src/index.ts +35 -0
@@ -0,0 +1,1243 @@
1
+ "use strict";
2
+
3
+ import { BigNumber } from "./bignumber";
4
+ import { defineReadOnly } from "./properties";
5
+
6
+ import { Logger } from "../logger";
7
+ const version = "fragments/5.7.0";
8
+ const logger = new Logger(version);
9
+
10
+ export interface JsonFragmentType {
11
+ readonly name?: string;
12
+ readonly indexed?: boolean;
13
+ readonly type?: string;
14
+ readonly internalType?: any; // @TODO: in v6 reduce type
15
+ readonly components?: ReadonlyArray<JsonFragmentType>;
16
+ }
17
+
18
+ export interface JsonFragment {
19
+ readonly name?: string;
20
+ readonly type?: string;
21
+
22
+ readonly anonymous?: boolean;
23
+
24
+ readonly payable?: boolean;
25
+ readonly constant?: boolean;
26
+ readonly stateMutability?: string;
27
+
28
+ readonly inputs?: ReadonlyArray<JsonFragmentType>;
29
+ readonly outputs?: ReadonlyArray<JsonFragmentType>;
30
+
31
+ readonly gas?: string;
32
+ }
33
+
34
+ const _constructorGuard = {};
35
+
36
+ // AST Node parser state
37
+ type ParseState = {
38
+ allowArray?: boolean;
39
+ allowName?: boolean;
40
+ allowParams?: boolean;
41
+ allowType?: boolean;
42
+ readArray?: boolean;
43
+ };
44
+
45
+ // AST Node
46
+ type ParseNode = {
47
+ parent?: any;
48
+ type?: string;
49
+ name?: string;
50
+ state?: ParseState;
51
+ indexed?: boolean;
52
+ components?: Array<ParseNode>;
53
+ };
54
+
55
+ let ModifiersBytes: { [name: string]: boolean } = {
56
+ calldata: true,
57
+ memory: true,
58
+ storage: true,
59
+ };
60
+ let ModifiersNest: { [name: string]: boolean } = {
61
+ calldata: true,
62
+ memory: true,
63
+ };
64
+ function checkModifier(type: string, name: string): boolean {
65
+ if (type === "bytes" || type === "string") {
66
+ if (ModifiersBytes[name]) {
67
+ return true;
68
+ }
69
+ } else if (type === "address") {
70
+ if (name === "payable") {
71
+ return true;
72
+ }
73
+ } else if (type.indexOf("[") >= 0 || type === "tuple") {
74
+ if (ModifiersNest[name]) {
75
+ return true;
76
+ }
77
+ }
78
+ if (ModifiersBytes[name] || name === "payable") {
79
+ logger.throwArgumentError("invalid modifier", "name", name);
80
+ }
81
+ return false;
82
+ }
83
+
84
+ // @TODO: Make sure that children of an indexed tuple are marked with a null indexed
85
+ function parseParamType(param: string, allowIndexed: boolean): ParseNode {
86
+ let originalParam = param;
87
+ function throwError(i: number) {
88
+ logger.throwArgumentError(
89
+ `unexpected character at position ${i}`,
90
+ "param",
91
+ param,
92
+ );
93
+ }
94
+ param = param.replace(/\s/g, " ");
95
+
96
+ function newNode(parent: ParseNode): ParseNode {
97
+ let node: ParseNode = {
98
+ type: "",
99
+ name: "",
100
+ parent: parent,
101
+ state: { allowType: true },
102
+ };
103
+ if (allowIndexed) {
104
+ node.indexed = false;
105
+ }
106
+ return node;
107
+ }
108
+
109
+ let parent: ParseNode = { type: "", name: "", state: { allowType: true } };
110
+ let node = parent;
111
+
112
+ for (let i = 0; i < param.length; i++) {
113
+ let c = param[i];
114
+ switch (c) {
115
+ case "(":
116
+ if (node.state.allowType && node.type === "") {
117
+ node.type = "tuple";
118
+ } else if (!node.state.allowParams) {
119
+ throwError(i);
120
+ }
121
+ node.state.allowType = false;
122
+ node.type = verifyType(node.type);
123
+ node.components = [newNode(node)];
124
+ node = node.components[0];
125
+ break;
126
+
127
+ case ")":
128
+ delete node.state;
129
+
130
+ if (node.name === "indexed") {
131
+ if (!allowIndexed) {
132
+ throwError(i);
133
+ }
134
+ node.indexed = true;
135
+ node.name = "";
136
+ }
137
+
138
+ if (checkModifier(node.type, node.name)) {
139
+ node.name = "";
140
+ }
141
+
142
+ node.type = verifyType(node.type);
143
+
144
+ let child = node;
145
+ node = node.parent;
146
+ if (!node) {
147
+ throwError(i);
148
+ }
149
+ delete child.parent;
150
+ node.state.allowParams = false;
151
+ node.state.allowName = true;
152
+ node.state.allowArray = true;
153
+ break;
154
+
155
+ case ",":
156
+ delete node.state;
157
+
158
+ if (node.name === "indexed") {
159
+ if (!allowIndexed) {
160
+ throwError(i);
161
+ }
162
+ node.indexed = true;
163
+ node.name = "";
164
+ }
165
+
166
+ if (checkModifier(node.type, node.name)) {
167
+ node.name = "";
168
+ }
169
+
170
+ node.type = verifyType(node.type);
171
+
172
+ let sibling: ParseNode = newNode(node.parent);
173
+ //{ type: "", name: "", parent: node.parent, state: { allowType: true } };
174
+ node.parent.components.push(sibling);
175
+ delete node.parent;
176
+ node = sibling;
177
+ break;
178
+
179
+ // Hit a space...
180
+ case " ":
181
+ // If reading type, the type is done and may read a param or name
182
+ if (node.state.allowType) {
183
+ if (node.type !== "") {
184
+ node.type = verifyType(node.type);
185
+ delete node.state.allowType;
186
+ node.state.allowName = true;
187
+ node.state.allowParams = true;
188
+ }
189
+ }
190
+
191
+ // If reading name, the name is done
192
+ if (node.state.allowName) {
193
+ if (node.name !== "") {
194
+ if (node.name === "indexed") {
195
+ if (!allowIndexed) {
196
+ throwError(i);
197
+ }
198
+ if (node.indexed) {
199
+ throwError(i);
200
+ }
201
+ node.indexed = true;
202
+ node.name = "";
203
+ } else if (checkModifier(node.type, node.name)) {
204
+ node.name = "";
205
+ } else {
206
+ node.state.allowName = false;
207
+ }
208
+ }
209
+ }
210
+
211
+ break;
212
+
213
+ case "[":
214
+ if (!node.state.allowArray) {
215
+ throwError(i);
216
+ }
217
+
218
+ node.type += c;
219
+
220
+ node.state.allowArray = false;
221
+ node.state.allowName = false;
222
+ node.state.readArray = true;
223
+ break;
224
+
225
+ case "]":
226
+ if (!node.state.readArray) {
227
+ throwError(i);
228
+ }
229
+
230
+ node.type += c;
231
+
232
+ node.state.readArray = false;
233
+ node.state.allowArray = true;
234
+ node.state.allowName = true;
235
+ break;
236
+
237
+ default:
238
+ if (node.state.allowType) {
239
+ node.type += c;
240
+ node.state.allowParams = true;
241
+ node.state.allowArray = true;
242
+ } else if (node.state.allowName) {
243
+ node.name += c;
244
+ delete node.state.allowArray;
245
+ } else if (node.state.readArray) {
246
+ node.type += c;
247
+ } else {
248
+ throwError(i);
249
+ }
250
+ }
251
+ }
252
+
253
+ if (node.parent) {
254
+ logger.throwArgumentError("unexpected eof", "param", param);
255
+ }
256
+
257
+ delete parent.state;
258
+
259
+ if (node.name === "indexed") {
260
+ if (!allowIndexed) {
261
+ throwError(originalParam.length - 7);
262
+ }
263
+ if (node.indexed) {
264
+ throwError(originalParam.length - 7);
265
+ }
266
+ node.indexed = true;
267
+ node.name = "";
268
+ } else if (checkModifier(node.type, node.name)) {
269
+ node.name = "";
270
+ }
271
+
272
+ parent.type = verifyType(parent.type);
273
+
274
+ return parent;
275
+ }
276
+
277
+ function populate(object: any, params: any) {
278
+ for (let key in params) {
279
+ defineReadOnly(object, key, params[key]);
280
+ }
281
+ }
282
+
283
+ export const FormatTypes: { [name: string]: string } = Object.freeze({
284
+ // Bare formatting, as is needed for computing a sighash of an event or function
285
+ sighash: "sighash",
286
+
287
+ // Human-Readable with Minimal spacing and without names (compact human-readable)
288
+ minimal: "minimal",
289
+
290
+ // Human-Readable with nice spacing, including all names
291
+ full: "full",
292
+
293
+ // JSON-format a la Solidity
294
+ json: "json",
295
+ });
296
+
297
+ const paramTypeArray = new RegExp(/^(.*)\[([0-9]*)\]$/);
298
+
299
+ export class ParamType {
300
+ // The local name of the parameter (of null if unbound)
301
+ readonly name: string;
302
+
303
+ // The fully qualified type (e.g. "address", "tuple(address)", "uint256[3][]"
304
+ readonly type: string;
305
+
306
+ // The base type (e.g. "address", "tuple", "array")
307
+ readonly baseType: string;
308
+
309
+ // Indexable Paramters ONLY (otherwise null)
310
+ readonly indexed: boolean;
311
+
312
+ // Tuples ONLY: (otherwise null)
313
+ // - sub-components
314
+ readonly components: Array<ParamType>;
315
+
316
+ // Arrays ONLY: (otherwise null)
317
+ // - length of the array (-1 for dynamic length)
318
+ // - child type
319
+ readonly arrayLength: number;
320
+ readonly arrayChildren: ParamType;
321
+
322
+ readonly _isParamType: boolean;
323
+
324
+ constructor(constructorGuard: any, params: any) {
325
+ if (constructorGuard !== _constructorGuard) {
326
+ logger.throwError("use fromString", Logger.errors.UNSUPPORTED_OPERATION, {
327
+ operation: "new ParamType()",
328
+ });
329
+ }
330
+ populate(this, params);
331
+
332
+ let match = this.type.match(paramTypeArray);
333
+ if (match) {
334
+ populate(this, {
335
+ arrayLength: parseInt(match[2] || "-1"),
336
+ arrayChildren: ParamType.fromObject({
337
+ type: match[1],
338
+ components: this.components,
339
+ }),
340
+ baseType: "array",
341
+ });
342
+ } else {
343
+ populate(this, {
344
+ arrayLength: null,
345
+ arrayChildren: null,
346
+ baseType: this.components != null ? "tuple" : this.type,
347
+ });
348
+ }
349
+
350
+ this._isParamType = true;
351
+
352
+ Object.freeze(this);
353
+ }
354
+
355
+ // Format the parameter fragment
356
+ // - sighash: "(uint256,address)"
357
+ // - minimal: "tuple(uint256,address) indexed"
358
+ // - full: "tuple(uint256 foo, address bar) indexed baz"
359
+ format(format?: string): string {
360
+ if (!format) {
361
+ format = FormatTypes.sighash;
362
+ }
363
+ if (!FormatTypes[format]) {
364
+ logger.throwArgumentError("invalid format type", "format", format);
365
+ }
366
+
367
+ if (format === FormatTypes.json) {
368
+ let result: any = {
369
+ type: this.baseType === "tuple" ? "tuple" : this.type,
370
+ name: this.name || undefined,
371
+ };
372
+ if (typeof this.indexed === "boolean") {
373
+ result.indexed = this.indexed;
374
+ }
375
+ if (this.components) {
376
+ result.components = this.components.map((comp) =>
377
+ JSON.parse(comp.format(format)),
378
+ );
379
+ }
380
+ return JSON.stringify(result);
381
+ }
382
+
383
+ let result = "";
384
+
385
+ // Array
386
+ if (this.baseType === "array") {
387
+ result += this.arrayChildren.format(format);
388
+ result +=
389
+ "[" + (this.arrayLength < 0 ? "" : String(this.arrayLength)) + "]";
390
+ } else {
391
+ if (this.baseType === "tuple") {
392
+ if (format !== FormatTypes.sighash) {
393
+ result += this.type;
394
+ }
395
+ result +=
396
+ "(" +
397
+ this.components
398
+ .map((comp) => comp.format(format))
399
+ .join(format === FormatTypes.full ? ", " : ",") +
400
+ ")";
401
+ } else {
402
+ result += this.type;
403
+ }
404
+ }
405
+
406
+ if (format !== FormatTypes.sighash) {
407
+ if (this.indexed === true) {
408
+ result += " indexed";
409
+ }
410
+ if (format === FormatTypes.full && this.name) {
411
+ result += " " + this.name;
412
+ }
413
+ }
414
+
415
+ return result;
416
+ }
417
+
418
+ static from(
419
+ value: string | JsonFragmentType | ParamType,
420
+ allowIndexed?: boolean,
421
+ ): ParamType {
422
+ if (typeof value === "string") {
423
+ return ParamType.fromString(value, allowIndexed);
424
+ }
425
+ return ParamType.fromObject(value);
426
+ }
427
+
428
+ static fromObject(value: JsonFragmentType | ParamType): ParamType {
429
+ if (ParamType.isParamType(value)) {
430
+ return value;
431
+ }
432
+
433
+ return new ParamType(_constructorGuard, {
434
+ name: value.name || null,
435
+ type: verifyType(value.type),
436
+ indexed: value.indexed == null ? null : !!value.indexed,
437
+ components: value.components
438
+ ? value.components.map(ParamType.fromObject)
439
+ : null,
440
+ });
441
+ }
442
+
443
+ static fromString(value: string, allowIndexed?: boolean): ParamType {
444
+ function ParamTypify(node: ParseNode): ParamType {
445
+ return ParamType.fromObject({
446
+ name: node.name,
447
+ type: node.type,
448
+ indexed: node.indexed,
449
+ components: node.components,
450
+ });
451
+ }
452
+
453
+ return ParamTypify(parseParamType(value, !!allowIndexed));
454
+ }
455
+
456
+ static isParamType(value: any): value is ParamType {
457
+ return !!(value != null && value._isParamType);
458
+ }
459
+ }
460
+
461
+ function parseParams(value: string, allowIndex: boolean): Array<ParamType> {
462
+ return splitNesting(value).map((param) =>
463
+ ParamType.fromString(param, allowIndex),
464
+ );
465
+ }
466
+
467
+ type TypeCheck<T> = { -readonly [K in keyof T]: T[K] };
468
+
469
+ interface _Fragment {
470
+ readonly type: string;
471
+ readonly name: string;
472
+ readonly inputs: ReadonlyArray<ParamType>;
473
+ }
474
+
475
+ export abstract class Fragment {
476
+ readonly type: string;
477
+ readonly name: string;
478
+ readonly inputs: Array<ParamType>;
479
+
480
+ readonly _isFragment: boolean;
481
+
482
+ constructor(constructorGuard: any, params: any) {
483
+ if (constructorGuard !== _constructorGuard) {
484
+ logger.throwError(
485
+ "use a static from method",
486
+ Logger.errors.UNSUPPORTED_OPERATION,
487
+ {
488
+ operation: "new Fragment()",
489
+ },
490
+ );
491
+ }
492
+ populate(this, params);
493
+
494
+ this._isFragment = true;
495
+
496
+ Object.freeze(this);
497
+ }
498
+
499
+ abstract format(format?: string): string;
500
+
501
+ static from(value: Fragment | JsonFragment | string): Fragment {
502
+ if (Fragment.isFragment(value)) {
503
+ return value;
504
+ }
505
+
506
+ if (typeof value === "string") {
507
+ return Fragment.fromString(value);
508
+ }
509
+
510
+ return Fragment.fromObject(value);
511
+ }
512
+
513
+ static fromObject(value: Fragment | JsonFragment): Fragment {
514
+ if (Fragment.isFragment(value)) {
515
+ return value;
516
+ }
517
+
518
+ switch (value.type) {
519
+ case "function":
520
+ return FunctionFragment.fromObject(value);
521
+ case "event":
522
+ return EventFragment.fromObject(value);
523
+ case "constructor":
524
+ return ConstructorFragment.fromObject(value);
525
+ case "error":
526
+ return ErrorFragment.fromObject(value);
527
+ case "fallback":
528
+ case "receive":
529
+ // @TODO: Something? Maybe return a FunctionFragment? A custom DefaultFunctionFragment?
530
+ return null;
531
+ }
532
+
533
+ return logger.throwArgumentError("invalid fragment object", "value", value);
534
+ }
535
+
536
+ static fromString(value: string): Fragment {
537
+ // Make sure the "returns" is surrounded by a space and all whitespace is exactly one space
538
+ value = value.replace(/\s/g, " ");
539
+ value = value
540
+ .replace(/\(/g, " (")
541
+ .replace(/\)/g, ") ")
542
+ .replace(/\s+/g, " ");
543
+ value = value.trim();
544
+
545
+ if (value.split(" ")[0] === "event") {
546
+ return EventFragment.fromString(value.substring(5).trim());
547
+ } else if (value.split(" ")[0] === "function") {
548
+ return FunctionFragment.fromString(value.substring(8).trim());
549
+ } else if (value.split("(")[0].trim() === "constructor") {
550
+ return ConstructorFragment.fromString(value.trim());
551
+ } else if (value.split(" ")[0] === "error") {
552
+ return ErrorFragment.fromString(value.substring(5).trim());
553
+ }
554
+
555
+ return logger.throwArgumentError("unsupported fragment", "value", value);
556
+ }
557
+
558
+ static isFragment(value: any): value is Fragment {
559
+ return !!(value && value._isFragment);
560
+ }
561
+ }
562
+
563
+ interface _EventFragment extends _Fragment {
564
+ readonly anonymous: boolean;
565
+ }
566
+
567
+ export class EventFragment extends Fragment {
568
+ readonly anonymous: boolean;
569
+
570
+ format(format?: string): string {
571
+ if (!format) {
572
+ format = FormatTypes.sighash;
573
+ }
574
+ if (!FormatTypes[format]) {
575
+ logger.throwArgumentError("invalid format type", "format", format);
576
+ }
577
+
578
+ if (format === FormatTypes.json) {
579
+ return JSON.stringify({
580
+ type: "event",
581
+ anonymous: this.anonymous,
582
+ name: this.name,
583
+ inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
584
+ });
585
+ }
586
+
587
+ let result = "";
588
+
589
+ if (format !== FormatTypes.sighash) {
590
+ result += "event ";
591
+ }
592
+
593
+ result +=
594
+ this.name +
595
+ "(" +
596
+ this.inputs
597
+ .map((input) => input.format(format))
598
+ .join(format === FormatTypes.full ? ", " : ",") +
599
+ ") ";
600
+
601
+ if (format !== FormatTypes.sighash) {
602
+ if (this.anonymous) {
603
+ result += "anonymous ";
604
+ }
605
+ }
606
+
607
+ return result.trim();
608
+ }
609
+
610
+ static from(value: EventFragment | JsonFragment | string): EventFragment {
611
+ if (typeof value === "string") {
612
+ return EventFragment.fromString(value);
613
+ }
614
+ return EventFragment.fromObject(value);
615
+ }
616
+
617
+ static fromObject(value: JsonFragment | EventFragment): EventFragment {
618
+ if (EventFragment.isEventFragment(value)) {
619
+ return value;
620
+ }
621
+
622
+ if (value.type !== "event") {
623
+ logger.throwArgumentError("invalid event object", "value", value);
624
+ }
625
+
626
+ const params: TypeCheck<_EventFragment> = {
627
+ name: verifyIdentifier(value.name),
628
+ anonymous: value.anonymous,
629
+ inputs: value.inputs ? value.inputs.map(ParamType.fromObject) : [],
630
+ type: "event",
631
+ };
632
+
633
+ return new EventFragment(_constructorGuard, params);
634
+ }
635
+
636
+ static fromString(value: string): EventFragment {
637
+ let match = value.match(regexParen);
638
+ if (!match) {
639
+ logger.throwArgumentError("invalid event string", "value", value);
640
+ }
641
+
642
+ let anonymous = false;
643
+ match[3].split(" ").forEach((modifier) => {
644
+ switch (modifier.trim()) {
645
+ case "anonymous":
646
+ anonymous = true;
647
+ break;
648
+ case "":
649
+ break;
650
+ default:
651
+ logger.warn("unknown modifier: " + modifier);
652
+ }
653
+ });
654
+
655
+ return EventFragment.fromObject({
656
+ name: match[1].trim(),
657
+ anonymous: anonymous,
658
+ inputs: parseParams(match[2], true),
659
+ type: "event",
660
+ });
661
+ }
662
+
663
+ static isEventFragment(value: any): value is EventFragment {
664
+ return value && value._isFragment && value.type === "event";
665
+ }
666
+ }
667
+
668
+ function parseGas(value: string, params: any): string {
669
+ params.gas = null;
670
+
671
+ let comps = value.split("@");
672
+ if (comps.length !== 1) {
673
+ if (comps.length > 2) {
674
+ logger.throwArgumentError(
675
+ "invalid human-readable ABI signature",
676
+ "value",
677
+ value,
678
+ );
679
+ }
680
+ if (!comps[1].match(/^[0-9]+$/)) {
681
+ logger.throwArgumentError(
682
+ "invalid human-readable ABI signature gas",
683
+ "value",
684
+ value,
685
+ );
686
+ }
687
+ params.gas = BigNumber.from(comps[1]);
688
+ return comps[0];
689
+ }
690
+
691
+ return value;
692
+ }
693
+
694
+ function parseModifiers(value: string, params: any): void {
695
+ params.constant = false;
696
+ params.payable = false;
697
+ params.stateMutability = "nonpayable";
698
+
699
+ value.split(" ").forEach((modifier) => {
700
+ switch (modifier.trim()) {
701
+ case "constant":
702
+ params.constant = true;
703
+ break;
704
+ case "payable":
705
+ params.payable = true;
706
+ params.stateMutability = "payable";
707
+ break;
708
+ case "nonpayable":
709
+ params.payable = false;
710
+ params.stateMutability = "nonpayable";
711
+ break;
712
+ case "pure":
713
+ params.constant = true;
714
+ params.stateMutability = "pure";
715
+ break;
716
+ case "view":
717
+ params.constant = true;
718
+ params.stateMutability = "view";
719
+ break;
720
+ case "external":
721
+ case "public":
722
+ case "":
723
+ break;
724
+ default:
725
+ console.log("unknown modifier: " + modifier);
726
+ }
727
+ });
728
+ }
729
+
730
+ type StateInputValue = {
731
+ constant?: boolean;
732
+ payable?: boolean;
733
+ stateMutability?: string;
734
+ type?: string;
735
+ };
736
+
737
+ type StateOutputValue = {
738
+ constant: boolean;
739
+ payable: boolean;
740
+ stateMutability: string;
741
+ };
742
+
743
+ function verifyState(value: StateInputValue): StateOutputValue {
744
+ let result: any = {
745
+ constant: false,
746
+ payable: true,
747
+ stateMutability: "payable",
748
+ };
749
+
750
+ if (value.stateMutability != null) {
751
+ result.stateMutability = value.stateMutability;
752
+
753
+ // Set (and check things are consistent) the constant property
754
+ result.constant =
755
+ result.stateMutability === "view" || result.stateMutability === "pure";
756
+ if (value.constant != null) {
757
+ if (!!value.constant !== result.constant) {
758
+ logger.throwArgumentError(
759
+ "cannot have constant function with mutability " +
760
+ result.stateMutability,
761
+ "value",
762
+ value,
763
+ );
764
+ }
765
+ }
766
+
767
+ // Set (and check things are consistent) the payable property
768
+ result.payable = result.stateMutability === "payable";
769
+ if (value.payable != null) {
770
+ if (!!value.payable !== result.payable) {
771
+ logger.throwArgumentError(
772
+ "cannot have payable function with mutability " +
773
+ result.stateMutability,
774
+ "value",
775
+ value,
776
+ );
777
+ }
778
+ }
779
+ } else if (value.payable != null) {
780
+ result.payable = !!value.payable;
781
+
782
+ // If payable we can assume non-constant; otherwise we can't assume
783
+ if (
784
+ value.constant == null &&
785
+ !result.payable &&
786
+ value.type !== "constructor"
787
+ ) {
788
+ logger.throwArgumentError(
789
+ "unable to determine stateMutability",
790
+ "value",
791
+ value,
792
+ );
793
+ }
794
+
795
+ result.constant = !!value.constant;
796
+
797
+ if (result.constant) {
798
+ result.stateMutability = "view";
799
+ } else {
800
+ result.stateMutability = result.payable ? "payable" : "nonpayable";
801
+ }
802
+
803
+ if (result.payable && result.constant) {
804
+ logger.throwArgumentError(
805
+ "cannot have constant payable function",
806
+ "value",
807
+ value,
808
+ );
809
+ }
810
+ } else if (value.constant != null) {
811
+ result.constant = !!value.constant;
812
+ result.payable = !result.constant;
813
+ result.stateMutability = result.constant ? "view" : "payable";
814
+ } else if (value.type !== "constructor") {
815
+ logger.throwArgumentError(
816
+ "unable to determine stateMutability",
817
+ "value",
818
+ value,
819
+ );
820
+ }
821
+
822
+ return result;
823
+ }
824
+
825
+ interface _ConstructorFragment extends _Fragment {
826
+ stateMutability: string;
827
+ payable: boolean;
828
+ gas?: BigNumber;
829
+ }
830
+
831
+ export class ConstructorFragment extends Fragment {
832
+ stateMutability: string;
833
+ payable: boolean;
834
+ gas?: BigNumber;
835
+
836
+ format(format?: string): string {
837
+ if (!format) {
838
+ format = FormatTypes.sighash;
839
+ }
840
+ if (!FormatTypes[format]) {
841
+ logger.throwArgumentError("invalid format type", "format", format);
842
+ }
843
+
844
+ if (format === FormatTypes.json) {
845
+ return JSON.stringify({
846
+ type: "constructor",
847
+ stateMutability:
848
+ this.stateMutability !== "nonpayable"
849
+ ? this.stateMutability
850
+ : undefined,
851
+ payable: this.payable,
852
+ gas: this.gas ? this.gas.toNumber() : undefined,
853
+ inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
854
+ });
855
+ }
856
+
857
+ if (format === FormatTypes.sighash) {
858
+ logger.throwError(
859
+ "cannot format a constructor for sighash",
860
+ Logger.errors.UNSUPPORTED_OPERATION,
861
+ {
862
+ operation: "format(sighash)",
863
+ },
864
+ );
865
+ }
866
+
867
+ let result =
868
+ "constructor(" +
869
+ this.inputs
870
+ .map((input) => input.format(format))
871
+ .join(format === FormatTypes.full ? ", " : ",") +
872
+ ") ";
873
+
874
+ if (this.stateMutability && this.stateMutability !== "nonpayable") {
875
+ result += this.stateMutability + " ";
876
+ }
877
+
878
+ return result.trim();
879
+ }
880
+
881
+ static from(
882
+ value: ConstructorFragment | JsonFragment | string,
883
+ ): ConstructorFragment {
884
+ if (typeof value === "string") {
885
+ return ConstructorFragment.fromString(value);
886
+ }
887
+ return ConstructorFragment.fromObject(value);
888
+ }
889
+
890
+ static fromObject(
891
+ value: ConstructorFragment | JsonFragment,
892
+ ): ConstructorFragment {
893
+ if (ConstructorFragment.isConstructorFragment(value)) {
894
+ return value;
895
+ }
896
+
897
+ if (value.type !== "constructor") {
898
+ logger.throwArgumentError("invalid constructor object", "value", value);
899
+ }
900
+
901
+ let state = verifyState(value);
902
+ if (state.constant) {
903
+ logger.throwArgumentError(
904
+ "constructor cannot be constant",
905
+ "value",
906
+ value,
907
+ );
908
+ }
909
+
910
+ const params: TypeCheck<_ConstructorFragment> = {
911
+ name: null,
912
+ type: value.type,
913
+ inputs: value.inputs ? value.inputs.map(ParamType.fromObject) : [],
914
+ payable: state.payable,
915
+ stateMutability: state.stateMutability,
916
+ gas: value.gas ? BigNumber.from(value.gas) : null,
917
+ };
918
+
919
+ return new ConstructorFragment(_constructorGuard, params);
920
+ }
921
+
922
+ static fromString(value: string): ConstructorFragment {
923
+ let params: any = { type: "constructor" };
924
+
925
+ value = parseGas(value, params);
926
+
927
+ console.log(value);
928
+ let parens = value.match(regexParen);
929
+ if (!parens || parens[1].trim() !== "constructor") {
930
+ logger.throwArgumentError("invalid constructor string", "value", value);
931
+ }
932
+
933
+ params.inputs = parseParams(parens[2].trim(), false);
934
+
935
+ parseModifiers(parens[3].trim(), params);
936
+
937
+ return ConstructorFragment.fromObject(params);
938
+ }
939
+
940
+ static isConstructorFragment(value: any): value is ConstructorFragment {
941
+ return value && value._isFragment && value.type === "constructor";
942
+ }
943
+ }
944
+
945
+ interface _FunctionFragment extends _ConstructorFragment {
946
+ constant: boolean;
947
+ outputs?: Array<ParamType>;
948
+ }
949
+
950
+ export class FunctionFragment extends ConstructorFragment {
951
+ constant: boolean;
952
+ outputs?: Array<ParamType>;
953
+
954
+ format(format?: string): string {
955
+ if (!format) {
956
+ format = FormatTypes.sighash;
957
+ }
958
+ if (!FormatTypes[format]) {
959
+ logger.throwArgumentError("invalid format type", "format", format);
960
+ }
961
+
962
+ if (format === FormatTypes.json) {
963
+ return JSON.stringify({
964
+ type: "function",
965
+ name: this.name,
966
+ constant: this.constant,
967
+ stateMutability:
968
+ this.stateMutability !== "nonpayable"
969
+ ? this.stateMutability
970
+ : undefined,
971
+ payable: this.payable,
972
+ gas: this.gas ? this.gas.toNumber() : undefined,
973
+ inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
974
+ outputs: this.outputs.map((output) =>
975
+ JSON.parse(output.format(format)),
976
+ ),
977
+ });
978
+ }
979
+
980
+ let result = "";
981
+
982
+ if (format !== FormatTypes.sighash) {
983
+ result += "function ";
984
+ }
985
+
986
+ result +=
987
+ this.name +
988
+ "(" +
989
+ this.inputs
990
+ .map((input) => input.format(format))
991
+ .join(format === FormatTypes.full ? ", " : ",") +
992
+ ") ";
993
+
994
+ if (format !== FormatTypes.sighash) {
995
+ if (this.stateMutability) {
996
+ if (this.stateMutability !== "nonpayable") {
997
+ result += this.stateMutability + " ";
998
+ }
999
+ } else if (this.constant) {
1000
+ result += "view ";
1001
+ }
1002
+
1003
+ if (this.outputs && this.outputs.length) {
1004
+ result +=
1005
+ "returns (" +
1006
+ this.outputs.map((output) => output.format(format)).join(", ") +
1007
+ ") ";
1008
+ }
1009
+
1010
+ if (this.gas != null) {
1011
+ result += "@" + this.gas.toString() + " ";
1012
+ }
1013
+ }
1014
+
1015
+ return result.trim();
1016
+ }
1017
+
1018
+ static from(
1019
+ value: FunctionFragment | JsonFragment | string,
1020
+ ): FunctionFragment {
1021
+ if (typeof value === "string") {
1022
+ return FunctionFragment.fromString(value);
1023
+ }
1024
+ return FunctionFragment.fromObject(value);
1025
+ }
1026
+
1027
+ static fromObject(value: FunctionFragment | JsonFragment): FunctionFragment {
1028
+ if (FunctionFragment.isFunctionFragment(value)) {
1029
+ return value;
1030
+ }
1031
+
1032
+ if (value.type !== "function") {
1033
+ logger.throwArgumentError("invalid function object", "value", value);
1034
+ }
1035
+
1036
+ let state = verifyState(value);
1037
+
1038
+ const params: TypeCheck<_FunctionFragment> = {
1039
+ type: value.type,
1040
+ name: verifyIdentifier(value.name),
1041
+ constant: state.constant,
1042
+ inputs: value.inputs ? value.inputs.map(ParamType.fromObject) : [],
1043
+ outputs: value.outputs ? value.outputs.map(ParamType.fromObject) : [],
1044
+ payable: state.payable,
1045
+ stateMutability: state.stateMutability,
1046
+ gas: value.gas ? BigNumber.from(value.gas) : null,
1047
+ };
1048
+
1049
+ return new FunctionFragment(_constructorGuard, params);
1050
+ }
1051
+
1052
+ static fromString(value: string): FunctionFragment {
1053
+ let params: any = { type: "function" };
1054
+ value = parseGas(value, params);
1055
+
1056
+ let comps = value.split(" returns ");
1057
+ if (comps.length > 2) {
1058
+ logger.throwArgumentError("invalid function string", "value", value);
1059
+ }
1060
+
1061
+ let parens = comps[0].match(regexParen);
1062
+ if (!parens) {
1063
+ logger.throwArgumentError("invalid function signature", "value", value);
1064
+ }
1065
+
1066
+ params.name = parens[1].trim();
1067
+ if (params.name) {
1068
+ verifyIdentifier(params.name);
1069
+ }
1070
+
1071
+ params.inputs = parseParams(parens[2], false);
1072
+
1073
+ parseModifiers(parens[3].trim(), params);
1074
+
1075
+ // We have outputs
1076
+ if (comps.length > 1) {
1077
+ let returns = comps[1].match(regexParen);
1078
+ if (returns[1].trim() != "" || returns[3].trim() != "") {
1079
+ logger.throwArgumentError("unexpected tokens", "value", value);
1080
+ }
1081
+ params.outputs = parseParams(returns[2], false);
1082
+ } else {
1083
+ params.outputs = [];
1084
+ }
1085
+
1086
+ return FunctionFragment.fromObject(params);
1087
+ }
1088
+
1089
+ static isFunctionFragment(value: any): value is FunctionFragment {
1090
+ return value && value._isFragment && value.type === "function";
1091
+ }
1092
+ }
1093
+
1094
+ //export class StructFragment extends Fragment {
1095
+ //}
1096
+
1097
+ function checkForbidden(fragment: ErrorFragment): ErrorFragment {
1098
+ const sig = fragment.format();
1099
+ if (sig === "Error(string)" || sig === "Panic(uint256)") {
1100
+ logger.throwArgumentError(
1101
+ `cannot specify user defined ${sig} error`,
1102
+ "fragment",
1103
+ fragment,
1104
+ );
1105
+ }
1106
+ return fragment;
1107
+ }
1108
+
1109
+ export class ErrorFragment extends Fragment {
1110
+ format(format?: string): string {
1111
+ if (!format) {
1112
+ format = FormatTypes.sighash;
1113
+ }
1114
+ if (!FormatTypes[format]) {
1115
+ logger.throwArgumentError("invalid format type", "format", format);
1116
+ }
1117
+
1118
+ if (format === FormatTypes.json) {
1119
+ return JSON.stringify({
1120
+ type: "error",
1121
+ name: this.name,
1122
+ inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
1123
+ });
1124
+ }
1125
+
1126
+ let result = "";
1127
+
1128
+ if (format !== FormatTypes.sighash) {
1129
+ result += "error ";
1130
+ }
1131
+
1132
+ result +=
1133
+ this.name +
1134
+ "(" +
1135
+ this.inputs
1136
+ .map((input) => input.format(format))
1137
+ .join(format === FormatTypes.full ? ", " : ",") +
1138
+ ") ";
1139
+
1140
+ return result.trim();
1141
+ }
1142
+
1143
+ static from(value: ErrorFragment | JsonFragment | string): ErrorFragment {
1144
+ if (typeof value === "string") {
1145
+ return ErrorFragment.fromString(value);
1146
+ }
1147
+ return ErrorFragment.fromObject(value);
1148
+ }
1149
+
1150
+ static fromObject(value: ErrorFragment | JsonFragment): ErrorFragment {
1151
+ if (ErrorFragment.isErrorFragment(value)) {
1152
+ return value;
1153
+ }
1154
+
1155
+ if (value.type !== "error") {
1156
+ logger.throwArgumentError("invalid error object", "value", value);
1157
+ }
1158
+
1159
+ const params: TypeCheck<_Fragment> = {
1160
+ type: value.type,
1161
+ name: verifyIdentifier(value.name),
1162
+ inputs: value.inputs ? value.inputs.map(ParamType.fromObject) : [],
1163
+ };
1164
+
1165
+ return checkForbidden(new ErrorFragment(_constructorGuard, params));
1166
+ }
1167
+
1168
+ static fromString(value: string): ErrorFragment {
1169
+ let params: any = { type: "error" };
1170
+
1171
+ let parens = value.match(regexParen);
1172
+ if (!parens) {
1173
+ logger.throwArgumentError("invalid error signature", "value", value);
1174
+ }
1175
+
1176
+ params.name = parens[1].trim();
1177
+ if (params.name) {
1178
+ verifyIdentifier(params.name);
1179
+ }
1180
+
1181
+ params.inputs = parseParams(parens[2], false);
1182
+
1183
+ return checkForbidden(ErrorFragment.fromObject(params));
1184
+ }
1185
+
1186
+ static isErrorFragment(value: any): value is ErrorFragment {
1187
+ return value && value._isFragment && value.type === "error";
1188
+ }
1189
+ }
1190
+
1191
+ function verifyType(type: string): string {
1192
+ // These need to be transformed to their full description
1193
+ if (type.match(/^uint($|[^1-9])/)) {
1194
+ type = "uint256" + type.substring(4);
1195
+ } else if (type.match(/^int($|[^1-9])/)) {
1196
+ type = "int256" + type.substring(3);
1197
+ }
1198
+
1199
+ // @TODO: more verification
1200
+
1201
+ return type;
1202
+ }
1203
+
1204
+ // See: https://github.com/ethereum/solidity/blob/1f8f1a3db93a548d0555e3e14cfc55a10e25b60e/docs/grammar/SolidityLexer.g4#L234
1205
+ const regexIdentifier = new RegExp("^[a-zA-Z$_][a-zA-Z0-9$_]*$");
1206
+ function verifyIdentifier(value: string): string {
1207
+ if (!value || !value.match(regexIdentifier)) {
1208
+ logger.throwArgumentError(`invalid identifier "${value}"`, "value", value);
1209
+ }
1210
+ return value;
1211
+ }
1212
+
1213
+ const regexParen = new RegExp("^([^)(]*)\\((.*)\\)([^)(]*)$");
1214
+
1215
+ function splitNesting(value: string): Array<any> {
1216
+ value = value.trim();
1217
+
1218
+ let result = [];
1219
+ let accum = "";
1220
+ let depth = 0;
1221
+ for (let offset = 0; offset < value.length; offset++) {
1222
+ let c = value[offset];
1223
+ if (c === "," && depth === 0) {
1224
+ result.push(accum);
1225
+ accum = "";
1226
+ } else {
1227
+ accum += c;
1228
+ if (c === "(") {
1229
+ depth++;
1230
+ } else if (c === ")") {
1231
+ depth--;
1232
+ if (depth === -1) {
1233
+ logger.throwArgumentError("unbalanced parenthesis", "value", value);
1234
+ }
1235
+ }
1236
+ }
1237
+ }
1238
+ if (accum) {
1239
+ result.push(accum);
1240
+ }
1241
+
1242
+ return result;
1243
+ }