1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const client_common_1 = require("@neo-one/client-common");
|
5 | const bignumber_js_1 = tslib_1.__importDefault(require("bignumber.js"));
|
6 | const bn_js_1 = require("bn.js");
|
7 | const crypto_1 = require("crypto");
|
8 | const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
9 | const toASCII = (bytes) => {
|
10 | let result = '';
|
11 | lodash_1.default.range(bytes.length).forEach((i) => {
|
12 | result += String.fromCharCode(bytes.readUInt8(i));
|
13 | });
|
14 | return result;
|
15 | };
|
16 | const toUTF8 = (bytes) => bytes.toString('utf8');
|
17 | const calculateClaimAmount = async ({ coins, decrementInterval, generationAmount, getSystemFee, }) => {
|
18 | const grouped = Object.values(lodash_1.default.groupBy(coins, (coin) => `${coin.startHeight}:${coin.endHeight}`));
|
19 | const claimed = await Promise.all(grouped.map(async (coinsGroup) => {
|
20 | const { startHeight, endHeight } = coinsGroup[0];
|
21 | let amount = client_common_1.utils.ZERO;
|
22 | let ustart = Math.floor(startHeight / decrementInterval);
|
23 | if (ustart < generationAmount.length) {
|
24 | let istart = startHeight % decrementInterval;
|
25 | let uend = Math.floor(endHeight / decrementInterval);
|
26 | let iend = endHeight % decrementInterval;
|
27 | if (uend >= generationAmount.length) {
|
28 | uend = generationAmount.length;
|
29 | iend = 0;
|
30 | }
|
31 | if (iend === 0) {
|
32 | uend -= 1;
|
33 | iend = decrementInterval;
|
34 | }
|
35 | while (ustart < uend) {
|
36 | amount = amount.addn((decrementInterval - istart) * generationAmount[ustart]);
|
37 | ustart += 1;
|
38 | istart = 0;
|
39 | }
|
40 | amount = amount.addn((iend - istart) * generationAmount[ustart]);
|
41 | }
|
42 | const [sysFeeEnd, sysFeeStart] = await Promise.all([
|
43 | getSystemFee(endHeight - 1),
|
44 | startHeight === 0 ? Promise.resolve(client_common_1.utils.ZERO) : getSystemFee(startHeight - 1),
|
45 | ]);
|
46 | amount = amount.add(sysFeeEnd.sub(sysFeeStart).div(client_common_1.utils.ONE_HUNDRED_MILLION));
|
47 | const totalValue = coinsGroup.reduce((acc, { value }) => acc.add(value), client_common_1.utils.ZERO);
|
48 | return [totalValue, amount];
|
49 | }));
|
50 | return claimed.reduce((acc, [value, amount]) => acc.add(value.div(client_common_1.utils.ONE_HUNDRED_MILLION).mul(amount)), client_common_1.utils.ZERO);
|
51 | };
|
52 | const randomUInt64 = () => new bn_js_1.BN(crypto_1.randomBytes(8).toString('hex'), 16);
|
53 | const toKeyString = (clazz, toKey) => () => `${clazz.name}:${toKey()}`;
|
54 | function lazyAsync(getValue) {
|
55 | let valuePromise;
|
56 | return async (input) => {
|
57 | if (valuePromise === undefined) {
|
58 | valuePromise = getValue(input);
|
59 | }
|
60 | return valuePromise;
|
61 | };
|
62 | }
|
63 | function lazyOrValue(getValue) {
|
64 | let settings = typeof getValue === 'function' ? { type: 'lazy', getValue } : { type: 'evaluated', value: getValue };
|
65 | return () => {
|
66 | if (settings.type === 'lazy') {
|
67 | settings = { type: 'evaluated', value: settings.getValue() };
|
68 | }
|
69 | return settings.value;
|
70 | };
|
71 | }
|
72 | function weightedAverage(input) {
|
73 | let sumWeight = new bignumber_js_1.default(0);
|
74 | let sumValue = new bignumber_js_1.default(0);
|
75 | input.forEach((value) => {
|
76 | sumWeight = sumWeight.plus(value.weight);
|
77 | sumValue = sumValue.plus(value.weight.times(value.value));
|
78 | });
|
79 | if (sumValue.isEqualTo(0) || sumWeight.isEqualTo(0)) {
|
80 | return 0;
|
81 | }
|
82 | return sumValue
|
83 | .div(sumWeight)
|
84 | .integerValue(bignumber_js_1.default.ROUND_FLOOR)
|
85 | .toNumber();
|
86 | }
|
87 | function weightedFilter(input, startIn, endIn, getValueIn) {
|
88 | const start = new bignumber_js_1.default(startIn);
|
89 | const end = new bignumber_js_1.default(endIn);
|
90 | const getValue = (value) => new bignumber_js_1.default(getValueIn(value).toString(10));
|
91 | const amount = input.reduce((acc, value) => acc.plus(getValue(value)), new bignumber_js_1.default(0));
|
92 | let sum = new bignumber_js_1.default(0);
|
93 | let current = new bignumber_js_1.default(0);
|
94 | const mutableResult = [];
|
95 | for (const value of input) {
|
96 | if (current.gte(end)) {
|
97 | break;
|
98 | }
|
99 | let weight = getValue(value);
|
100 | sum = sum.plus(weight);
|
101 | const old = current;
|
102 | current = sum.div(amount);
|
103 | if (current.lte(start)) {
|
104 | continue;
|
105 | }
|
106 | if (old.lt(start)) {
|
107 | weight = current.gt(end) ? end.minus(start).times(amount) : current.minus(start).times(amount);
|
108 | }
|
109 | else if (current.gt(end)) {
|
110 | weight = end.minus(old).times(amount);
|
111 | }
|
112 | mutableResult.push([
|
113 | value,
|
114 | weight.gte(0) ? weight.integerValue(bignumber_js_1.default.ROUND_FLOOR) : weight.integerValue(bignumber_js_1.default.ROUND_CEIL),
|
115 | ]);
|
116 | }
|
117 | return mutableResult;
|
118 | }
|
119 | function equals(clazz, thiz, equalsFunc) {
|
120 | return (other) => other != undefined && (thiz === other || (other instanceof clazz && equalsFunc(other)));
|
121 | }
|
122 | exports.utils = Object.assign(Object.assign({}, client_common_1.utils), { toASCII,
|
123 | toUTF8,
|
124 | calculateClaimAmount,
|
125 | randomUInt64,
|
126 | toKeyString,
|
127 | equals,
|
128 | lazyAsync,
|
129 | lazyOrValue,
|
130 | weightedAverage,
|
131 | weightedFilter });
|
132 |
|
133 |
|