@leofcoin/chain 1.10.8 → 1.10.10

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.
@@ -30,6 +30,907 @@ class TransactionMessage extends FormatInterface {
30
30
  }
31
31
  }
32
32
 
33
+ /* Do NOT modify this file; see /src.ts/_admin/update-version.ts */
34
+ /**
35
+ * The current version of Ethers.
36
+ */
37
+ const version = "6.17.0";
38
+
39
+ /**
40
+ * Property helper functions.
41
+ *
42
+ * @_subsection api/utils:Properties [about-properties]
43
+ */
44
+ /**
45
+ * Assigns the %%values%% to %%target%% as read-only values.
46
+ *
47
+ * It %%types%% is specified, the values are checked.
48
+ */
49
+ function defineProperties(target, values, types) {
50
+ for (let key in values) {
51
+ let value = values[key];
52
+ Object.defineProperty(target, key, { enumerable: true, value, writable: false });
53
+ }
54
+ }
55
+
56
+ /**
57
+ * All errors in ethers include properties to ensure they are both
58
+ * human-readable (i.e. ``.message``) and machine-readable (i.e. ``.code``).
59
+ *
60
+ * The [[isError]] function can be used to check the error ``code`` and
61
+ * provide a type guard for the properties present on that error interface.
62
+ *
63
+ * @_section: api/utils/errors:Errors [about-errors]
64
+ */
65
+ function stringify(value, seen) {
66
+ if (value == null) {
67
+ return "null";
68
+ }
69
+ if (seen == null) {
70
+ seen = new Set();
71
+ }
72
+ if (typeof (value) === "object") {
73
+ if (seen.has(value)) {
74
+ return "[Circular]";
75
+ }
76
+ seen.add(value);
77
+ }
78
+ if (Array.isArray(value)) {
79
+ return "[ " + (value.map((v) => stringify(v, seen))).join(", ") + " ]";
80
+ }
81
+ if (value instanceof Uint8Array) {
82
+ const HEX = "0123456789abcdef";
83
+ let result = "0x";
84
+ for (let i = 0; i < value.length; i++) {
85
+ result += HEX[value[i] >> 4];
86
+ result += HEX[value[i] & 0xf];
87
+ }
88
+ return result;
89
+ }
90
+ if (typeof (value) === "object" && typeof (value.toJSON) === "function") {
91
+ return stringify(value.toJSON(), seen);
92
+ }
93
+ switch (typeof (value)) {
94
+ case "boolean":
95
+ case "number":
96
+ case "symbol":
97
+ return value.toString();
98
+ case "bigint":
99
+ return BigInt(value).toString();
100
+ case "string":
101
+ return JSON.stringify(value);
102
+ case "object": {
103
+ const keys = Object.keys(value);
104
+ keys.sort();
105
+ return "{ " + keys.map((k) => `${stringify(k, seen)}: ${stringify(value[k], seen)}`).join(", ") + " }";
106
+ }
107
+ }
108
+ return `[ COULD NOT SERIALIZE ]`;
109
+ }
110
+ /**
111
+ * Returns a new Error configured to the format ethers emits errors, with
112
+ * the %%message%%, [[api:ErrorCode]] %%code%% and additional properties
113
+ * for the corresponding EthersError.
114
+ *
115
+ * Each error in ethers includes the version of ethers, a
116
+ * machine-readable [[ErrorCode]], and depending on %%code%%, additional
117
+ * required properties. The error message will also include the %%message%%,
118
+ * ethers version, %%code%% and all additional properties, serialized.
119
+ */
120
+ function makeError(message, code, info) {
121
+ let shortMessage = message;
122
+ {
123
+ const details = [];
124
+ if (info) {
125
+ if ("message" in info || "code" in info || "name" in info) {
126
+ throw new Error(`value will overwrite populated values: ${stringify(info)}`);
127
+ }
128
+ for (const key in info) {
129
+ if (key === "shortMessage") {
130
+ continue;
131
+ }
132
+ const value = (info[key]);
133
+ // try {
134
+ details.push(key + "=" + stringify(value));
135
+ // } catch (error: any) {
136
+ // console.log("MMM", error.message);
137
+ // details.push(key + "=[could not serialize object]");
138
+ // }
139
+ }
140
+ }
141
+ details.push(`code=${code}`);
142
+ details.push(`version=${version}`);
143
+ if (details.length) {
144
+ message += " (" + details.join(", ") + ")";
145
+ }
146
+ }
147
+ let error;
148
+ switch (code) {
149
+ case "INVALID_ARGUMENT":
150
+ error = new TypeError(message);
151
+ break;
152
+ case "NUMERIC_FAULT":
153
+ case "BUFFER_OVERRUN":
154
+ error = new RangeError(message);
155
+ break;
156
+ default:
157
+ error = new Error(message);
158
+ }
159
+ defineProperties(error, { code });
160
+ if (info) {
161
+ Object.assign(error, info);
162
+ }
163
+ if (error.shortMessage == null) {
164
+ defineProperties(error, { shortMessage });
165
+ }
166
+ return error;
167
+ }
168
+ /**
169
+ * Throws an EthersError with %%message%%, %%code%% and additional error
170
+ * %%info%% when %%check%% is falsish..
171
+ *
172
+ * @see [[api:makeError]]
173
+ */
174
+ function assert(check, message, code, info) {
175
+ if (!check) {
176
+ throw makeError(message, code, info);
177
+ }
178
+ }
179
+ /**
180
+ * A simple helper to simply ensuring provided arguments match expected
181
+ * constraints, throwing if not.
182
+ *
183
+ * In TypeScript environments, the %%check%% has been asserted true, so
184
+ * any further code does not need additional compile-time checks.
185
+ */
186
+ function assertArgument(check, message, name, value) {
187
+ assert(check, message, "INVALID_ARGUMENT", { argument: name, value: value });
188
+ }
189
+ ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
190
+ try {
191
+ // General test for normalize
192
+ /* c8 ignore start */
193
+ if ("test".normalize(form) !== "test") {
194
+ throw new Error("bad");
195
+ }
196
+ ;
197
+ /* c8 ignore stop */
198
+ if (form === "NFD") {
199
+ const check = String.fromCharCode(0xe9).normalize("NFD");
200
+ const expected = String.fromCharCode(0x65, 0x0301);
201
+ /* c8 ignore start */
202
+ if (check !== expected) {
203
+ throw new Error("broken");
204
+ }
205
+ /* c8 ignore stop */
206
+ }
207
+ accum.push(form);
208
+ }
209
+ catch (error) { }
210
+ return accum;
211
+ }, []);
212
+ /**
213
+ * Many classes use file-scoped values to guard the constructor,
214
+ * making it effectively private. This facilitates that pattern
215
+ * by ensuring the %%givenGaurd%% matches the file-scoped %%guard%%,
216
+ * throwing if not, indicating the %%className%% if provided.
217
+ */
218
+ function assertPrivate(givenGuard, guard, className) {
219
+ if (givenGuard !== guard) {
220
+ let method = className, operation = "new";
221
+ {
222
+ method += ".";
223
+ operation += " " + className;
224
+ }
225
+ assert(false, `private constructor; use ${method}from* methods`, "UNSUPPORTED_OPERATION", {
226
+ operation
227
+ });
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Some data helpers.
233
+ *
234
+ *
235
+ * @_subsection api/utils:Data Helpers [about-data]
236
+ */
237
+ function _getBytes(value, name, copy) {
238
+ if (value instanceof Uint8Array) {
239
+ return value;
240
+ }
241
+ if (typeof (value) === "string" && (value.length % 2) === 0 &&
242
+ value.match(/^0x[0-9a-f]*$/i)) {
243
+ const result = new Uint8Array((value.length - 2) / 2);
244
+ let offset = 2;
245
+ for (let i = 0; i < result.length; i++) {
246
+ result[i] = parseInt(value.substring(offset, offset + 2), 16);
247
+ offset += 2;
248
+ }
249
+ return result;
250
+ }
251
+ assertArgument(false, "invalid BytesLike value", name, value);
252
+ }
253
+ /**
254
+ * Get a typed Uint8Array for %%value%%. If already a Uint8Array
255
+ * the original %%value%% is returned; if a copy is required use
256
+ * [[getBytesCopy]].
257
+ *
258
+ * @see: getBytesCopy
259
+ */
260
+ function getBytes(value, name) {
261
+ return _getBytes(value, name);
262
+ }
263
+
264
+ /**
265
+ * Some mathematic operations.
266
+ *
267
+ * @_subsection: api/utils:Math Helpers [about-maths]
268
+ */
269
+ const BN_0$1 = BigInt(0);
270
+ const BN_1$1 = BigInt(1);
271
+ //const BN_Max256 = (BN_1 << BigInt(256)) - BN_1;
272
+ // IEEE 754 support 53-bits of mantissa
273
+ const maxValue = 0x1fffffffffffff;
274
+ /**
275
+ * Convert %%value%% from a twos-compliment representation of %%width%%
276
+ * bits to its value.
277
+ *
278
+ * If the highest bit is ``1``, the result will be negative.
279
+ */
280
+ function fromTwos(_value, _width) {
281
+ const value = getUint(_value, "value");
282
+ const width = BigInt(getNumber(_width, "width"));
283
+ assert((value >> width) === BN_0$1, "overflow", "NUMERIC_FAULT", {
284
+ operation: "fromTwos", fault: "overflow", value: _value
285
+ });
286
+ // Top bit set; treat as a negative value
287
+ if (value >> (width - BN_1$1)) {
288
+ const mask = (BN_1$1 << width) - BN_1$1;
289
+ return -(((~value) & mask) + BN_1$1);
290
+ }
291
+ return value;
292
+ }
293
+ /**
294
+ * Mask %%value%% with a bitmask of %%bits%% ones.
295
+ */
296
+ function mask(_value, _bits) {
297
+ const value = getUint(_value, "value");
298
+ const bits = BigInt(getNumber(_bits, "bits"));
299
+ return value & ((BN_1$1 << bits) - BN_1$1);
300
+ }
301
+ /**
302
+ * Gets a BigInt from %%value%%. If it is an invalid value for
303
+ * a BigInt, then an ArgumentError will be thrown for %%name%%.
304
+ */
305
+ function getBigInt(value, name) {
306
+ switch (typeof (value)) {
307
+ case "bigint": return value;
308
+ case "number":
309
+ assertArgument(Number.isInteger(value), "underflow", name || "value", value);
310
+ assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
311
+ return BigInt(value);
312
+ case "string":
313
+ try {
314
+ if (value === "") {
315
+ throw new Error("empty string");
316
+ }
317
+ if (value[0] === "-" && value[1] !== "-") {
318
+ return -BigInt(value.substring(1));
319
+ }
320
+ return BigInt(value);
321
+ }
322
+ catch (e) {
323
+ assertArgument(false, `invalid BigNumberish string: ${e.message}`, name || "value", value);
324
+ }
325
+ }
326
+ assertArgument(false, "invalid BigNumberish value", name || "value", value);
327
+ }
328
+ /**
329
+ * Returns %%value%% as a bigint, validating it is valid as a bigint
330
+ * value and that it is positive.
331
+ */
332
+ function getUint(value, name) {
333
+ const result = getBigInt(value, name);
334
+ assert(result >= BN_0$1, "unsigned value cannot be negative", "NUMERIC_FAULT", {
335
+ fault: "overflow", operation: "getUint", value
336
+ });
337
+ return result;
338
+ }
339
+ const Nibbles = "0123456789abcdef";
340
+ /*
341
+ * Converts %%value%% to a BigInt. If %%value%% is a Uint8Array, it
342
+ * is treated as Big Endian data.
343
+ */
344
+ function toBigInt(value) {
345
+ if (value instanceof Uint8Array) {
346
+ let result = "0x0";
347
+ for (const v of value) {
348
+ result += Nibbles[v >> 4];
349
+ result += Nibbles[v & 0x0f];
350
+ }
351
+ return BigInt(result);
352
+ }
353
+ return getBigInt(value);
354
+ }
355
+ /**
356
+ * Gets a //number// from %%value%%. If it is an invalid value for
357
+ * a //number//, then an ArgumentError will be thrown for %%name%%.
358
+ */
359
+ function getNumber(value, name) {
360
+ switch (typeof (value)) {
361
+ case "bigint":
362
+ assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
363
+ return Number(value);
364
+ case "number":
365
+ assertArgument(Number.isInteger(value), "underflow", name || "value", value);
366
+ assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
367
+ return value;
368
+ case "string":
369
+ try {
370
+ if (value === "") {
371
+ throw new Error("empty string");
372
+ }
373
+ return getNumber(BigInt(value), name);
374
+ }
375
+ catch (e) {
376
+ assertArgument(false, `invalid numeric string: ${e.message}`, name || "value", value);
377
+ }
378
+ }
379
+ assertArgument(false, "invalid numeric value", name || "value", value);
380
+ }
381
+
382
+ /**
383
+ * The **FixedNumber** class permits using values with decimal places,
384
+ * using fixed-pont math.
385
+ *
386
+ * Fixed-point math is still based on integers under-the-hood, but uses an
387
+ * internal offset to store fractional components below, and each operation
388
+ * corrects for this after each operation.
389
+ *
390
+ * @_section: api/utils/fixed-point-math:Fixed-Point Maths [about-fixed-point-math]
391
+ */
392
+ const BN_N1 = BigInt(-1);
393
+ const BN_0 = BigInt(0);
394
+ const BN_1 = BigInt(1);
395
+ const BN_5 = BigInt(5);
396
+ const _guard = {};
397
+ // Constant to pull zeros from for multipliers
398
+ let Zeros = "0000";
399
+ while (Zeros.length < 80) {
400
+ Zeros += Zeros;
401
+ }
402
+ // Returns a string "1" followed by decimal "0"s
403
+ function getTens(decimals) {
404
+ let result = Zeros;
405
+ while (result.length < decimals) {
406
+ result += result;
407
+ }
408
+ return BigInt("1" + result.substring(0, decimals));
409
+ }
410
+ function checkValue(val, format, safeOp) {
411
+ const width = BigInt(format.width);
412
+ if (format.signed) {
413
+ const limit = (BN_1 << (width - BN_1));
414
+ assert(safeOp == null || (val >= -limit && val < limit), "overflow", "NUMERIC_FAULT", {
415
+ operation: safeOp, fault: "overflow", value: val
416
+ });
417
+ if (val > BN_0) {
418
+ val = fromTwos(mask(val, width), width);
419
+ }
420
+ else {
421
+ val = -fromTwos(mask(-val, width), width);
422
+ }
423
+ }
424
+ else {
425
+ const limit = (BN_1 << width);
426
+ assert(safeOp == null || (val >= 0 && val < limit), "overflow", "NUMERIC_FAULT", {
427
+ operation: safeOp, fault: "overflow", value: val
428
+ });
429
+ val = (((val % limit) + limit) % limit) & (limit - BN_1);
430
+ }
431
+ return val;
432
+ }
433
+ function getFormat(value) {
434
+ if (typeof (value) === "number") {
435
+ value = `fixed128x${value}`;
436
+ }
437
+ let signed = true;
438
+ let width = 128;
439
+ let decimals = 18;
440
+ if (typeof (value) === "string") {
441
+ // Parse the format string
442
+ if (value === "fixed") ;
443
+ else if (value === "ufixed") {
444
+ signed = false;
445
+ }
446
+ else {
447
+ const match = value.match(/^(u?)fixed([0-9]+)x([0-9]+)$/);
448
+ assertArgument(match, "invalid fixed format", "format", value);
449
+ signed = (match[1] !== "u");
450
+ width = parseInt(match[2]);
451
+ decimals = parseInt(match[3]);
452
+ }
453
+ }
454
+ else if (value) {
455
+ // Extract the values from the object
456
+ const v = value;
457
+ const check = (key, type, defaultValue) => {
458
+ if (v[key] == null) {
459
+ return defaultValue;
460
+ }
461
+ assertArgument(typeof (v[key]) === type, "invalid fixed format (" + key + " not " + type + ")", "format." + key, v[key]);
462
+ return v[key];
463
+ };
464
+ signed = check("signed", "boolean", signed);
465
+ width = check("width", "number", width);
466
+ decimals = check("decimals", "number", decimals);
467
+ }
468
+ assertArgument((width % 8) === 0, "invalid FixedNumber width (not byte aligned)", "format.width", width);
469
+ assertArgument(decimals <= 80, "invalid FixedNumber decimals (too large)", "format.decimals", decimals);
470
+ const name = (signed ? "" : "u") + "fixed" + String(width) + "x" + String(decimals);
471
+ return { signed, width, decimals, name };
472
+ }
473
+ function toString(val, decimals) {
474
+ let negative = "";
475
+ if (val < BN_0) {
476
+ negative = "-";
477
+ val *= BN_N1;
478
+ }
479
+ let str = val.toString();
480
+ // No decimal point for whole values
481
+ if (decimals === 0) {
482
+ return (negative + str);
483
+ }
484
+ // Pad out to the whole component (including a whole digit)
485
+ while (str.length <= decimals) {
486
+ str = Zeros + str;
487
+ }
488
+ // Insert the decimal point
489
+ const index = str.length - decimals;
490
+ str = str.substring(0, index) + "." + str.substring(index);
491
+ // Trim the whole component (leaving at least one 0)
492
+ while (str[0] === "0" && str[1] !== ".") {
493
+ str = str.substring(1);
494
+ }
495
+ // Trim the decimal component (leaving at least one 0)
496
+ while (str[str.length - 1] === "0" && str[str.length - 2] !== ".") {
497
+ str = str.substring(0, str.length - 1);
498
+ }
499
+ return (negative + str);
500
+ }
501
+ /**
502
+ * A FixedNumber represents a value over its [[FixedFormat]]
503
+ * arithmetic field.
504
+ *
505
+ * A FixedNumber can be used to perform math, losslessly, on
506
+ * values which have decmial places.
507
+ *
508
+ * A FixedNumber has a fixed bit-width to store values in, and stores all
509
+ * values internally by multiplying the value by 10 raised to the power of
510
+ * %%decimals%%.
511
+ *
512
+ * If operations are performed that cause a value to grow too high (close to
513
+ * positive infinity) or too low (close to negative infinity), the value
514
+ * is said to //overflow//.
515
+ *
516
+ * For example, an 8-bit signed value, with 0 decimals may only be within
517
+ * the range ``-128`` to ``127``; so ``-128 - 1`` will overflow and become
518
+ * ``127``. Likewise, ``127 + 1`` will overflow and become ``-127``.
519
+ *
520
+ * Many operation have a normal and //unsafe// variant. The normal variant
521
+ * will throw a [[NumericFaultError]] on any overflow, while the //unsafe//
522
+ * variant will silently allow overflow, corrupting its value value.
523
+ *
524
+ * If operations are performed that cause a value to become too small
525
+ * (close to zero), the value loses precison and is said to //underflow//.
526
+ *
527
+ * For example, a value with 1 decimal place may store a number as small
528
+ * as ``0.1``, but the value of ``0.1 / 2`` is ``0.05``, which cannot fit
529
+ * into 1 decimal place, so underflow occurs which means precision is lost
530
+ * and the value becomes ``0``.
531
+ *
532
+ * Some operations have a normal and //signalling// variant. The normal
533
+ * variant will silently ignore underflow, while the //signalling// variant
534
+ * will thow a [[NumericFaultError]] on underflow.
535
+ */
536
+ class FixedNumber {
537
+ /**
538
+ * The specific fixed-point arithmetic field for this value.
539
+ */
540
+ format;
541
+ #format;
542
+ // The actual value (accounting for decimals)
543
+ #val;
544
+ // A base-10 value to multiple values by to maintain the magnitude
545
+ #tens;
546
+ /**
547
+ * This is a property so console.log shows a human-meaningful value.
548
+ *
549
+ * @private
550
+ */
551
+ _value;
552
+ // Use this when changing this file to get some typing info,
553
+ // but then switch to any to mask the internal type
554
+ //constructor(guard: any, value: bigint, format: _FixedFormat) {
555
+ /**
556
+ * @private
557
+ */
558
+ constructor(guard, value, format) {
559
+ assertPrivate(guard, _guard, "FixedNumber");
560
+ this.#val = value;
561
+ this.#format = format;
562
+ const _value = toString(value, format.decimals);
563
+ defineProperties(this, { format: format.name, _value });
564
+ this.#tens = getTens(format.decimals);
565
+ }
566
+ /**
567
+ * If true, negative values are permitted, otherwise only
568
+ * positive values and zero are allowed.
569
+ */
570
+ get signed() { return this.#format.signed; }
571
+ /**
572
+ * The number of bits available to store the value.
573
+ */
574
+ get width() { return this.#format.width; }
575
+ /**
576
+ * The number of decimal places in the fixed-point arithment field.
577
+ */
578
+ get decimals() { return this.#format.decimals; }
579
+ /**
580
+ * The value as an integer, based on the smallest unit the
581
+ * [[decimals]] allow.
582
+ */
583
+ get value() { return this.#val; }
584
+ #checkFormat(other) {
585
+ assertArgument(this.format === other.format, "incompatible format; use fixedNumber.toFormat", "other", other);
586
+ }
587
+ #checkValue(val, safeOp) {
588
+ /*
589
+ const width = BigInt(this.width);
590
+ if (this.signed) {
591
+ const limit = (BN_1 << (width - BN_1));
592
+ assert(safeOp == null || (val >= -limit && val < limit), "overflow", "NUMERIC_FAULT", {
593
+ operation: <string>safeOp, fault: "overflow", value: val
594
+ });
595
+
596
+ if (val > BN_0) {
597
+ val = fromTwos(mask(val, width), width);
598
+ } else {
599
+ val = -fromTwos(mask(-val, width), width);
600
+ }
601
+
602
+ } else {
603
+ const masked = mask(val, width);
604
+ assert(safeOp == null || (val >= 0 && val === masked), "overflow", "NUMERIC_FAULT", {
605
+ operation: <string>safeOp, fault: "overflow", value: val
606
+ });
607
+ val = masked;
608
+ }
609
+ */
610
+ val = checkValue(val, this.#format, safeOp);
611
+ return new FixedNumber(_guard, val, this.#format);
612
+ }
613
+ #add(o, safeOp) {
614
+ this.#checkFormat(o);
615
+ return this.#checkValue(this.#val + o.#val, safeOp);
616
+ }
617
+ /**
618
+ * Returns a new [[FixedNumber]] with the result of %%this%% added
619
+ * to %%other%%, ignoring overflow.
620
+ */
621
+ addUnsafe(other) { return this.#add(other); }
622
+ /**
623
+ * Returns a new [[FixedNumber]] with the result of %%this%% added
624
+ * to %%other%%. A [[NumericFaultError]] is thrown if overflow
625
+ * occurs.
626
+ */
627
+ add(other) { return this.#add(other, "add"); }
628
+ #sub(o, safeOp) {
629
+ this.#checkFormat(o);
630
+ return this.#checkValue(this.#val - o.#val, safeOp);
631
+ }
632
+ /**
633
+ * Returns a new [[FixedNumber]] with the result of %%other%% subtracted
634
+ * from %%this%%, ignoring overflow.
635
+ */
636
+ subUnsafe(other) { return this.#sub(other); }
637
+ /**
638
+ * Returns a new [[FixedNumber]] with the result of %%other%% subtracted
639
+ * from %%this%%. A [[NumericFaultError]] is thrown if overflow
640
+ * occurs.
641
+ */
642
+ sub(other) { return this.#sub(other, "sub"); }
643
+ #mul(o, safeOp) {
644
+ this.#checkFormat(o);
645
+ return this.#checkValue((this.#val * o.#val) / this.#tens, safeOp);
646
+ }
647
+ /**
648
+ * Returns a new [[FixedNumber]] with the result of %%this%% multiplied
649
+ * by %%other%%, ignoring overflow and underflow (precision loss).
650
+ */
651
+ mulUnsafe(other) { return this.#mul(other); }
652
+ /**
653
+ * Returns a new [[FixedNumber]] with the result of %%this%% multiplied
654
+ * by %%other%%. A [[NumericFaultError]] is thrown if overflow
655
+ * occurs.
656
+ */
657
+ mul(other) { return this.#mul(other, "mul"); }
658
+ /**
659
+ * Returns a new [[FixedNumber]] with the result of %%this%% multiplied
660
+ * by %%other%%. A [[NumericFaultError]] is thrown if overflow
661
+ * occurs or if underflow (precision loss) occurs.
662
+ */
663
+ mulSignal(other) {
664
+ this.#checkFormat(other);
665
+ const value = this.#val * other.#val;
666
+ assert((value % this.#tens) === BN_0, "precision lost during signalling mul", "NUMERIC_FAULT", {
667
+ operation: "mulSignal", fault: "underflow", value: this
668
+ });
669
+ return this.#checkValue(value / this.#tens, "mulSignal");
670
+ }
671
+ #div(o, safeOp) {
672
+ assert(o.#val !== BN_0, "division by zero", "NUMERIC_FAULT", {
673
+ operation: "div", fault: "divide-by-zero", value: this
674
+ });
675
+ this.#checkFormat(o);
676
+ return this.#checkValue((this.#val * this.#tens) / o.#val, safeOp);
677
+ }
678
+ /**
679
+ * Returns a new [[FixedNumber]] with the result of %%this%% divided
680
+ * by %%other%%, ignoring underflow (precision loss). A
681
+ * [[NumericFaultError]] is thrown if overflow occurs.
682
+ */
683
+ divUnsafe(other) { return this.#div(other); }
684
+ /**
685
+ * Returns a new [[FixedNumber]] with the result of %%this%% divided
686
+ * by %%other%%, ignoring underflow (precision loss). A
687
+ * [[NumericFaultError]] is thrown if overflow occurs.
688
+ */
689
+ div(other) { return this.#div(other, "div"); }
690
+ /**
691
+ * Returns a new [[FixedNumber]] with the result of %%this%% divided
692
+ * by %%other%%. A [[NumericFaultError]] is thrown if underflow
693
+ * (precision loss) occurs.
694
+ */
695
+ divSignal(other) {
696
+ assert(other.#val !== BN_0, "division by zero", "NUMERIC_FAULT", {
697
+ operation: "div", fault: "divide-by-zero", value: this
698
+ });
699
+ this.#checkFormat(other);
700
+ const value = (this.#val * this.#tens);
701
+ assert((value % other.#val) === BN_0, "precision lost during signalling div", "NUMERIC_FAULT", {
702
+ operation: "divSignal", fault: "underflow", value: this
703
+ });
704
+ return this.#checkValue(value / other.#val, "divSignal");
705
+ }
706
+ /**
707
+ * Returns a comparison result between %%this%% and %%other%%.
708
+ *
709
+ * This is suitable for use in sorting, where ``-1`` implies %%this%%
710
+ * is smaller, ``1`` implies %%this%% is larger and ``0`` implies
711
+ * both are equal.
712
+ */
713
+ cmp(other) {
714
+ let a = this.value, b = other.value;
715
+ // Coerce a and b to the same magnitude
716
+ const delta = this.decimals - other.decimals;
717
+ if (delta > 0) {
718
+ b *= getTens(delta);
719
+ }
720
+ else if (delta < 0) {
721
+ a *= getTens(-delta);
722
+ }
723
+ // Comnpare
724
+ if (a < b) {
725
+ return -1;
726
+ }
727
+ if (a > b) {
728
+ return 1;
729
+ }
730
+ return 0;
731
+ }
732
+ /**
733
+ * Returns true if %%other%% is equal to %%this%%.
734
+ */
735
+ eq(other) { return this.cmp(other) === 0; }
736
+ /**
737
+ * Returns true if %%other%% is less than to %%this%%.
738
+ */
739
+ lt(other) { return this.cmp(other) < 0; }
740
+ /**
741
+ * Returns true if %%other%% is less than or equal to %%this%%.
742
+ */
743
+ lte(other) { return this.cmp(other) <= 0; }
744
+ /**
745
+ * Returns true if %%other%% is greater than to %%this%%.
746
+ */
747
+ gt(other) { return this.cmp(other) > 0; }
748
+ /**
749
+ * Returns true if %%other%% is greater than or equal to %%this%%.
750
+ */
751
+ gte(other) { return this.cmp(other) >= 0; }
752
+ /**
753
+ * Returns a new [[FixedNumber]] which is the largest **integer**
754
+ * that is less than or equal to %%this%%.
755
+ *
756
+ * The decimal component of the result will always be ``0``.
757
+ */
758
+ floor() {
759
+ let val = this.#val;
760
+ if (this.#val < BN_0) {
761
+ val -= this.#tens - BN_1;
762
+ }
763
+ val = (this.#val / this.#tens) * this.#tens;
764
+ return this.#checkValue(val, "floor");
765
+ }
766
+ /**
767
+ * Returns a new [[FixedNumber]] which is the smallest **integer**
768
+ * that is greater than or equal to %%this%%.
769
+ *
770
+ * The decimal component of the result will always be ``0``.
771
+ */
772
+ ceiling() {
773
+ let val = this.#val;
774
+ if (this.#val > BN_0) {
775
+ val += this.#tens - BN_1;
776
+ }
777
+ val = (this.#val / this.#tens) * this.#tens;
778
+ return this.#checkValue(val, "ceiling");
779
+ }
780
+ /**
781
+ * Returns a new [[FixedNumber]] with the decimal component
782
+ * rounded up on ties at %%decimals%% places.
783
+ */
784
+ round(decimals) {
785
+ if (decimals == null) {
786
+ decimals = 0;
787
+ }
788
+ // Not enough precision to not already be rounded
789
+ if (decimals >= this.decimals) {
790
+ return this;
791
+ }
792
+ const delta = this.decimals - decimals;
793
+ const bump = BN_5 * getTens(delta - 1);
794
+ let value = this.value + bump;
795
+ const tens = getTens(delta);
796
+ value = (value / tens) * tens;
797
+ checkValue(value, this.#format, "round");
798
+ return new FixedNumber(_guard, value, this.#format);
799
+ }
800
+ /**
801
+ * Returns true if %%this%% is equal to ``0``.
802
+ */
803
+ isZero() { return (this.#val === BN_0); }
804
+ /**
805
+ * Returns true if %%this%% is less than ``0``.
806
+ */
807
+ isNegative() { return (this.#val < BN_0); }
808
+ /**
809
+ * Returns the string representation of %%this%%.
810
+ */
811
+ toString() { return this._value; }
812
+ /**
813
+ * Returns a float approximation.
814
+ *
815
+ * Due to IEEE 754 precission (or lack thereof), this function
816
+ * can only return an approximation and most values will contain
817
+ * rounding errors.
818
+ */
819
+ toUnsafeFloat() { return parseFloat(this.toString()); }
820
+ /**
821
+ * Return a new [[FixedNumber]] with the same value but has had
822
+ * its field set to %%format%%.
823
+ *
824
+ * This will throw if the value cannot fit into %%format%%.
825
+ */
826
+ toFormat(format) {
827
+ return FixedNumber.fromString(this.toString(), format);
828
+ }
829
+ /**
830
+ * Creates a new [[FixedNumber]] for %%value%% divided by
831
+ * %%decimal%% places with %%format%%.
832
+ *
833
+ * This will throw a [[NumericFaultError]] if %%value%% (once adjusted
834
+ * for %%decimals%%) cannot fit in %%format%%, either due to overflow
835
+ * or underflow (precision loss).
836
+ */
837
+ static fromValue(_value, _decimals, _format) {
838
+ const decimals = (_decimals == null) ? 0 : getNumber(_decimals);
839
+ const format = getFormat(_format);
840
+ let value = getBigInt(_value, "value");
841
+ const delta = decimals - format.decimals;
842
+ if (delta > 0) {
843
+ const tens = getTens(delta);
844
+ assert((value % tens) === BN_0, "value loses precision for format", "NUMERIC_FAULT", {
845
+ operation: "fromValue", fault: "underflow", value: _value
846
+ });
847
+ value /= tens;
848
+ }
849
+ else if (delta < 0) {
850
+ value *= getTens(-delta);
851
+ }
852
+ checkValue(value, format, "fromValue");
853
+ return new FixedNumber(_guard, value, format);
854
+ }
855
+ /**
856
+ * Creates a new [[FixedNumber]] for %%value%% with %%format%%.
857
+ *
858
+ * This will throw a [[NumericFaultError]] if %%value%% cannot fit
859
+ * in %%format%%, either due to overflow or underflow (precision loss).
860
+ */
861
+ static fromString(_value, _format) {
862
+ const match = _value.match(/^(-?)([0-9]*)\.?([0-9]*)$/);
863
+ assertArgument(match && (match[2].length + match[3].length) > 0, "invalid FixedNumber string value", "value", _value);
864
+ const format = getFormat(_format);
865
+ let whole = (match[2] || "0"), decimal = (match[3] || "");
866
+ // Pad out the decimals
867
+ while (decimal.length < format.decimals) {
868
+ decimal += Zeros;
869
+ }
870
+ // Check precision is safe
871
+ assert(decimal.substring(format.decimals).match(/^0*$/), "too many decimals for format", "NUMERIC_FAULT", {
872
+ operation: "fromString", fault: "underflow", value: _value
873
+ });
874
+ // Remove extra padding
875
+ decimal = decimal.substring(0, format.decimals);
876
+ const value = BigInt(match[1] + whole + decimal);
877
+ checkValue(value, format, "fromString");
878
+ return new FixedNumber(_guard, value, format);
879
+ }
880
+ /**
881
+ * Creates a new [[FixedNumber]] with the big-endian representation
882
+ * %%value%% with %%format%%.
883
+ *
884
+ * This will throw a [[NumericFaultError]] if %%value%% cannot fit
885
+ * in %%format%% due to overflow.
886
+ */
887
+ static fromBytes(_value, _format) {
888
+ let value = toBigInt(getBytes(_value, "value"));
889
+ const format = getFormat(_format);
890
+ if (format.signed) {
891
+ value = fromTwos(value, format.width);
892
+ }
893
+ checkValue(value, format, "fromBytes");
894
+ return new FixedNumber(_guard, value, format);
895
+ }
896
+ }
897
+ //const f1 = FixedNumber.fromString("12.56", "fixed16x2");
898
+ //const f2 = FixedNumber.fromString("0.3", "fixed16x2");
899
+ //console.log(f1.divSignal(f2));
900
+ //const BUMP = FixedNumber.from("0.5");
901
+
902
+ /**
903
+ * Most interactions with Ethereum requires integer values, which use
904
+ * the smallest magnitude unit.
905
+ *
906
+ * For example, imagine dealing with dollars and cents. Since dollars
907
+ * are divisible, non-integer values are possible, such as ``$10.77``.
908
+ * By using the smallest indivisible unit (i.e. cents), the value can
909
+ * be kept as the integer ``1077``.
910
+ *
911
+ * When receiving decimal input from the user (as a decimal string),
912
+ * the value should be converted to an integer and when showing a user
913
+ * a value, the integer value should be converted to a decimal string.
914
+ *
915
+ * This creates a clear distinction, between values to be used by code
916
+ * (integers) and values used for display logic to users (decimals).
917
+ *
918
+ * The native unit in Ethereum, //ether// is divisible to 18 decimal places,
919
+ * where each individual unit is called a //wei//.
920
+ *
921
+ * @_subsection api/utils:Unit Conversion [about-units]
922
+ */
923
+ /**
924
+ * Converts %%value%% into a //decimal string//, assuming %%unit%% decimal
925
+ * places. The %%unit%% may be the number of decimal places or the name of
926
+ * a unit (e.g. ``"gwei"`` for 9 decimal places).
927
+ *
928
+ */
929
+ function formatUnits(value, unit) {
930
+ let decimals = 18;
931
+ return FixedNumber.fromValue(value, decimals, { decimals, width: 512 }).toString();
932
+ }
933
+
33
934
  const byteFormats = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
34
935
  const formatBytes = (bytes, decimals = 2) => {
35
936
  if (bytes === 0)
@@ -74,6 +975,132 @@ var bytecodes = {
74
975
  validators: validators
75
976
  };
76
977
 
978
+ const TRANSACTION_FEE_BYTES = 1024n;
979
+ const TRANSACTION_FEE_UNIT = 10n;
980
+ const MAX_TRANSACTION_BYTES = 32 * 1024;
981
+ const MAX_BLOCK_TRANSACTION_BYTES = 128 * 1024;
982
+ const MAX_BLOCK_TRANSACTIONS = 256;
983
+ (BigInt(MAX_TRANSACTION_BYTES) / TRANSACTION_FEE_BYTES) * TRANSACTION_FEE_UNIT;
984
+ const FEE_BASIS_POINTS = 10000n;
985
+ const FEE_PROTOCOL_VERSION = '1.10.9';
986
+ const MONETARY_POLICY_PROTOCOL_VERSION = '1.10.10';
987
+ const BLOCKS_PER_YEAR = 5256000n;
988
+ const ANNUAL_ISSUANCE_BASIS_POINTS = 200n;
989
+ const SUPPLY_FLOOR_BASIS_POINTS = 9500n;
990
+ const MONETARY_FEE_BURN_BASIS_POINTS = 1000n;
991
+ const parseProtocolVersion = (version) => {
992
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version);
993
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : undefined;
994
+ };
995
+ const supportsTransactionFees = (version) => {
996
+ const actual = parseProtocolVersion(version);
997
+ const required = parseProtocolVersion(FEE_PROTOCOL_VERSION);
998
+ if (!actual)
999
+ return false;
1000
+ for (let index = 0; index < required.length; index += 1) {
1001
+ if (actual[index] !== required[index])
1002
+ return actual[index] > required[index];
1003
+ }
1004
+ return true;
1005
+ };
1006
+ const supportsMonetaryPolicy = (version) => {
1007
+ const actual = parseProtocolVersion(version);
1008
+ const required = parseProtocolVersion(MONETARY_POLICY_PROTOCOL_VERSION);
1009
+ if (!actual)
1010
+ return false;
1011
+ for (let index = 0; index < required.length; index += 1) {
1012
+ if (actual[index] !== required[index])
1013
+ return actual[index] > required[index];
1014
+ }
1015
+ return true;
1016
+ };
1017
+ const calculateMonetaryPolicy = (totalSupply, targetSupply) => {
1018
+ if (totalSupply < 0n || targetSupply <= 0n)
1019
+ throw new Error('invalid monetary policy supply');
1020
+ const floorSupply = (targetSupply * SUPPLY_FLOOR_BASIS_POINTS) / FEE_BASIS_POINTS;
1021
+ if (totalSupply < floorSupply) {
1022
+ const annualIssuance = (targetSupply * ANNUAL_ISSUANCE_BASIS_POINTS) / FEE_BASIS_POINTS;
1023
+ const scheduled = annualIssuance / BLOCKS_PER_YEAR || 1n;
1024
+ return { subsidy: scheduled < floorSupply - totalSupply ? scheduled : floorSupply - totalSupply, burnBasisPoints: 0n, floorSupply };
1025
+ }
1026
+ return {
1027
+ subsidy: 0n,
1028
+ burnBasisPoints: totalSupply >= targetSupply ? MONETARY_FEE_BURN_BASIS_POINTS : 0n,
1029
+ floorSupply
1030
+ };
1031
+ };
1032
+ const distributeAmount = (amount, addresses, rotation = 0) => {
1033
+ const canonical = [...new Set(addresses)].sort();
1034
+ if (canonical.length === 0)
1035
+ throw new Error('cannot distribute without validators');
1036
+ const count = BigInt(canonical.length);
1037
+ const base = amount / count;
1038
+ const remainder = Number(amount % count);
1039
+ const result = new Map(canonical.map((address) => [address, base]));
1040
+ for (let index = 0; index < remainder; index += 1) {
1041
+ const address = canonical[(rotation + index) % canonical.length];
1042
+ result.set(address, result.get(address) + 1n);
1043
+ }
1044
+ return result;
1045
+ };
1046
+ const feeRotationIndex = (transactionHash, validatorCount) => {
1047
+ let value = 0n;
1048
+ for (const character of transactionHash)
1049
+ value = (value * 31n + BigInt(character.charCodeAt(0))) % 4294967291n;
1050
+ return Number(value % BigInt(validatorCount));
1051
+ };
1052
+ const distributeTransactionFee = (fee, transactionHash, validatorAddresses, burnBasisPoints = 1000n) => {
1053
+ const canonicalValidators = [...new Set(validatorAddresses)].sort();
1054
+ if (canonicalValidators.length === 0)
1055
+ throw new Error('cannot distribute transaction fee without validators');
1056
+ if (fee < 0n)
1057
+ throw new Error('transaction fee cannot be negative');
1058
+ if (burnBasisPoints < 0n || burnBasisPoints > FEE_BASIS_POINTS)
1059
+ throw new Error('invalid fee burn rate');
1060
+ const burned = (fee * burnBasisPoints) / FEE_BASIS_POINTS;
1061
+ const validatorPool = fee - burned;
1062
+ const count = BigInt(canonicalValidators.length);
1063
+ const base = validatorPool / count;
1064
+ const remainder = Number(validatorPool % count);
1065
+ const start = feeRotationIndex(transactionHash, canonicalValidators.length);
1066
+ const validatorFees = new Map(canonicalValidators.map((validator) => [validator, base]));
1067
+ for (let index = 0; index < remainder; index += 1) {
1068
+ const validator = canonicalValidators[(start + index) % canonicalValidators.length];
1069
+ validatorFees.set(validator, validatorFees.get(validator) + 1n);
1070
+ }
1071
+ const payments = [...validatorFees.entries()]
1072
+ .filter(([, amount]) => amount > 0n)
1073
+ .map(([to, amount]) => ({ to, amount }));
1074
+ return { burned, validatorFees, payments };
1075
+ };
1076
+ const calculateFee = async (transaction, format = false) => {
1077
+ transaction = await new TransactionMessage(transaction);
1078
+ const encodedBytes = BigInt(transaction.encoded.length);
1079
+ const units = (encodedBytes + TRANSACTION_FEE_BYTES - 1n) / TRANSACTION_FEE_BYTES;
1080
+ const fee = units * TRANSACTION_FEE_UNIT;
1081
+ return format ? formatUnits(fee.toString()) : fee;
1082
+ };
1083
+ const validateTransactionResourceLimits = async (transaction) => {
1084
+ const message = await new TransactionMessage(transaction);
1085
+ const size = message.encoded.length;
1086
+ if (size > MAX_TRANSACTION_BYTES) {
1087
+ throw new Error(`transaction exceeds ${MAX_TRANSACTION_BYTES} byte protocol limit: ${size}`);
1088
+ }
1089
+ return size;
1090
+ };
1091
+ const validateBlockResourceLimits = async (transactions) => {
1092
+ if (transactions.length > MAX_BLOCK_TRANSACTIONS) {
1093
+ throw new Error(`block exceeds ${MAX_BLOCK_TRANSACTIONS} transaction protocol limit`);
1094
+ }
1095
+ let size = 0;
1096
+ for (const transaction of transactions)
1097
+ size += await validateTransactionResourceLimits(transaction);
1098
+ if (size > MAX_BLOCK_TRANSACTION_BYTES) {
1099
+ throw new Error(`block transactions exceed ${MAX_BLOCK_TRANSACTION_BYTES} byte protocol limit: ${size}`);
1100
+ }
1101
+ return size;
1102
+ };
1103
+
77
1104
  class LittlePubSub {
78
1105
  subscribers = new Map();
79
1106
  verbose;
@@ -254,7 +1281,7 @@ const runTask = async (id, taskName, input) => {
254
1281
  });
255
1282
  }
256
1283
  };
257
- const _executeTransaction = async (transaction) => {
1284
+ const _executeTransaction = async (transaction, validators, feesEnabled, burnBasisPoints) => {
258
1285
  const hash = await new TransactionMessage(transaction).hash();
259
1286
  if (latestTransactions.includes(hash)) {
260
1287
  throw new Error(`double transaction found: ${hash}`);
@@ -264,6 +1291,11 @@ const _executeTransaction = async (transaction) => {
264
1291
  const { from, to, method, params, nonce } = transaction;
265
1292
  globalThis.msg = createMessage(from, to);
266
1293
  globalThis.state = await createState();
1294
+ if (feesEnabled) {
1295
+ const fee = BigInt(await calculateFee(transaction));
1296
+ const { payments, burned } = distributeTransactionFee(fee, hash, validators, burnBasisPoints);
1297
+ await _.collectFee({ from, payments, burned });
1298
+ }
267
1299
  await _.execute({ contract: to, method, params });
268
1300
  worker.postMessage({
269
1301
  type: 'transactionLoaded',
@@ -303,9 +1335,11 @@ const _ = {
303
1335
  });
304
1336
  }
305
1337
  },
306
- execute: async ({ contract, method, params }) => {
1338
+ execute: async ({ contract, method, params, sender }) => {
307
1339
  try {
308
1340
  let result;
1341
+ if (sender)
1342
+ globalThis.msg = createMessage(sender, contract);
309
1343
  // don't execute the method on a proxy
310
1344
  if (contracts[contract].fallback) {
311
1345
  result = await contracts[contract].fallback(method, params);
@@ -345,6 +1379,35 @@ const _ = {
345
1379
  `);
346
1380
  }
347
1381
  },
1382
+ collectFee: ({ from, payments, burned = 0n }) => {
1383
+ burned = BigInt(burned);
1384
+ const total = payments.reduce((sum, payment) => sum + BigInt(payment.amount), burned);
1385
+ const balance = BigInt(contracts[nativeToken$2].balanceOf(from) || 0n);
1386
+ if (balance < total)
1387
+ throw new Error(`insufficient balance for transaction fee: need ${total}, got ${balance}`);
1388
+ globalThis.msg = createMessage(from, nativeToken$2);
1389
+ for (const payment of payments) {
1390
+ const amount = BigInt(payment.amount);
1391
+ if (amount > 0n)
1392
+ contracts[nativeToken$2].transfer(from, payment.to, amount);
1393
+ }
1394
+ if (burned > 0n) {
1395
+ globalThis.msg = createMessage(contracts[nativeToken$2].creator, nativeToken$2);
1396
+ contracts[nativeToken$2].burn(from, burned);
1397
+ }
1398
+ return total;
1399
+ },
1400
+ settleRewards: ({ rewards }) => {
1401
+ globalThis.msg = createMessage(contracts[nativeToken$2].creator, nativeToken$2);
1402
+ let minted = 0n;
1403
+ for (const [validator, rawAmount] of rewards) {
1404
+ const amount = BigInt(rawAmount);
1405
+ if (amount > 0n)
1406
+ contracts[nativeToken$2].mint(validator, amount);
1407
+ minted += amount;
1408
+ }
1409
+ return minted;
1410
+ },
348
1411
  init: async (message) => {
349
1412
  let { peerid, fromState, state, info } = message;
350
1413
  if (info)
@@ -447,16 +1510,29 @@ const _ = {
447
1510
  }
448
1511
  return message;
449
1512
  }));
450
- const priority = transactions
451
- .filter((transaction) => transaction.priority)
452
- ?.sort((a, b) => a.nonce - b.nonce);
453
- if (priority.length > 0)
454
- for (const transaction of priority) {
455
- await _executeTransaction(transaction);
456
- }
457
- await Promise.all(transactions
458
- .filter((transaction) => !transaction.priority)
459
- .map(async (transaction) => _executeTransaction(transaction)));
1513
+ const validators = block.validators.map(({ address }) => address);
1514
+ transactions.sort((a, b) => {
1515
+ if (a.priority !== b.priority)
1516
+ return a.priority ? -1 : 1;
1517
+ const left = BigInt(a.nonce);
1518
+ const right = BigInt(b.nonce);
1519
+ return left < right ? -1 : left > right ? 1 : 0;
1520
+ });
1521
+ const feesEnabled = supportsTransactionFees(block.protocolVersion);
1522
+ const monetaryPolicyEnabled = supportsMonetaryPolicy(block.protocolVersion);
1523
+ if (monetaryPolicyEnabled)
1524
+ await validateBlockResourceLimits(transactions);
1525
+ const policy = monetaryPolicyEnabled
1526
+ ? calculateMonetaryPolicy(BigInt(contracts[nativeToken$2].totalSupply), BigInt(contracts[nativeToken$2].targetSupply))
1527
+ : { subsidy: 0n, burnBasisPoints: 1000n };
1528
+ for (const transaction of transactions) {
1529
+ await _executeTransaction(transaction, validators, feesEnabled, policy.burnBasisPoints);
1530
+ }
1531
+ if (monetaryPolicyEnabled && policy.subsidy > 0n) {
1532
+ _.settleRewards({
1533
+ rewards: [...distributeAmount(policy.subsidy, validators, Number(block.index) % validators.length)]
1534
+ });
1535
+ }
460
1536
  block.loaded = true;
461
1537
  worker.postMessage({
462
1538
  type: 'debug',
@@ -521,6 +1597,12 @@ worker.onmessage(({ id, type, input }) => {
521
1597
  case 'addLoadedBlock':
522
1598
  runTask(id, 'addLoadedBlock', input);
523
1599
  break;
1600
+ case 'collectFee':
1601
+ runTask(id, 'collectFee', input);
1602
+ break;
1603
+ case 'settleRewards':
1604
+ runTask(id, 'settleRewards', input);
1605
+ break;
524
1606
  case 'contracts':
525
1607
  respond(id, contracts);
526
1608
  break;