@glowlabs-org/utils 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -4
- package/dist/cjs/constants/addresses.d.ts +3 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +942 -302
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/abis/erc20.abi.d.ts +13 -0
- package/dist/cjs/lib/abis/forwarderABI.d.ts +99 -0
- package/dist/cjs/lib/hooks/use-forwarder.d.ts +36 -0
- package/dist/esm/constants/addresses.d.ts +3 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +942 -303
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/abis/erc20.abi.d.ts +13 -0
- package/dist/esm/lib/abis/forwarderABI.d.ts +99 -0
- package/dist/esm/lib/hooks/use-forwarder.d.ts +36 -0
- package/package.json +3 -2
- package/src/constants/addresses.ts +34 -0
- package/src/index.ts +2 -0
- package/src/lib/abis/erc20.abi.ts +49 -0
- package/src/lib/abis/forwarderABI.ts +69 -0
- package/src/lib/create-weekly-report/index.ts +149 -47
- package/src/lib/hooks/use-forwarder.ts +564 -0
package/dist/esm/index.js
CHANGED
@@ -5,7 +5,7 @@ import require$$3 from 'http';
|
|
5
5
|
import require$$4 from 'https';
|
6
6
|
import require$$0$1 from 'url';
|
7
7
|
import require$$6 from 'fs';
|
8
|
-
import
|
8
|
+
import require$$8 from 'crypto';
|
9
9
|
import require$$4$1 from 'assert';
|
10
10
|
import zlib from 'zlib';
|
11
11
|
import { EventEmitter } from 'events';
|
@@ -16,7 +16,7 @@ import Decimal from 'decimal.js';
|
|
16
16
|
|
17
17
|
const GENESIS_TIMESTAMP = 1700352000;
|
18
18
|
|
19
|
-
function bind$
|
19
|
+
function bind$2(fn, thisArg) {
|
20
20
|
return function wrap() {
|
21
21
|
return fn.apply(thisArg, arguments);
|
22
22
|
};
|
@@ -156,6 +156,27 @@ const isPlainObject = (val) => {
|
|
156
156
|
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(toStringTag$1 in val) && !(iterator in val);
|
157
157
|
};
|
158
158
|
|
159
|
+
/**
|
160
|
+
* Determine if a value is an empty object (safely handles Buffers)
|
161
|
+
*
|
162
|
+
* @param {*} val The value to test
|
163
|
+
*
|
164
|
+
* @returns {boolean} True if value is an empty object, otherwise false
|
165
|
+
*/
|
166
|
+
const isEmptyObject = (val) => {
|
167
|
+
// Early return for non-objects or Buffers to prevent RangeError
|
168
|
+
if (!isObject(val) || isBuffer$1(val)) {
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
|
172
|
+
try {
|
173
|
+
return Object.keys(val).length === 0 && Object.getPrototypeOf(val) === Object.prototype;
|
174
|
+
} catch (e) {
|
175
|
+
// Fallback for any other objects that might cause RangeError with Object.keys()
|
176
|
+
return false;
|
177
|
+
}
|
178
|
+
};
|
179
|
+
|
159
180
|
/**
|
160
181
|
* Determine if a value is a Date
|
161
182
|
*
|
@@ -278,6 +299,11 @@ function forEach(obj, fn, {allOwnKeys = false} = {}) {
|
|
278
299
|
fn.call(null, obj[i], i, obj);
|
279
300
|
}
|
280
301
|
} else {
|
302
|
+
// Buffer check
|
303
|
+
if (isBuffer$1(obj)) {
|
304
|
+
return;
|
305
|
+
}
|
306
|
+
|
281
307
|
// Iterate over object keys
|
282
308
|
const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
|
283
309
|
const len = keys.length;
|
@@ -291,6 +317,10 @@ function forEach(obj, fn, {allOwnKeys = false} = {}) {
|
|
291
317
|
}
|
292
318
|
|
293
319
|
function findKey(obj, key) {
|
320
|
+
if (isBuffer$1(obj)){
|
321
|
+
return null;
|
322
|
+
}
|
323
|
+
|
294
324
|
key = key.toLowerCase();
|
295
325
|
const keys = Object.keys(obj);
|
296
326
|
let i = keys.length;
|
@@ -365,7 +395,7 @@ function merge(/* obj1, obj2, obj3, ... */) {
|
|
365
395
|
const extend = (a, b, thisArg, {allOwnKeys}= {}) => {
|
366
396
|
forEach(b, (val, key) => {
|
367
397
|
if (thisArg && isFunction$1(val)) {
|
368
|
-
a[key] = bind$
|
398
|
+
a[key] = bind$2(val, thisArg);
|
369
399
|
} else {
|
370
400
|
a[key] = val;
|
371
401
|
}
|
@@ -644,6 +674,11 @@ const toJSONObject = (obj) => {
|
|
644
674
|
return;
|
645
675
|
}
|
646
676
|
|
677
|
+
//Buffer check
|
678
|
+
if (isBuffer$1(source)) {
|
679
|
+
return source;
|
680
|
+
}
|
681
|
+
|
647
682
|
if(!('toJSON' in source)) {
|
648
683
|
stack[i] = source;
|
649
684
|
const target = isArray(source) ? [] : {};
|
@@ -715,6 +750,7 @@ var utils$1 = {
|
|
715
750
|
isBoolean,
|
716
751
|
isObject,
|
717
752
|
isPlainObject,
|
753
|
+
isEmptyObject,
|
718
754
|
isReadableStream,
|
719
755
|
isRequest,
|
720
756
|
isResponse,
|
@@ -12515,7 +12551,7 @@ var abs$1 = Math.abs;
|
|
12515
12551
|
var floor$1 = Math.floor;
|
12516
12552
|
|
12517
12553
|
/** @type {import('./max')} */
|
12518
|
-
var max$
|
12554
|
+
var max$2 = Math.max;
|
12519
12555
|
|
12520
12556
|
/** @type {import('./min')} */
|
12521
12557
|
var min$1 = Math.min;
|
@@ -12672,110 +12708,92 @@ function requireObject_getPrototypeOf () {
|
|
12672
12708
|
return Object_getPrototypeOf;
|
12673
12709
|
}
|
12674
12710
|
|
12675
|
-
|
12676
|
-
var hasRequiredImplementation;
|
12677
|
-
|
12678
|
-
function requireImplementation () {
|
12679
|
-
if (hasRequiredImplementation) return implementation;
|
12680
|
-
hasRequiredImplementation = 1;
|
12681
|
-
|
12682
|
-
/* eslint no-invalid-this: 1 */
|
12683
|
-
|
12684
|
-
var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
|
12685
|
-
var toStr = Object.prototype.toString;
|
12686
|
-
var max = Math.max;
|
12687
|
-
var funcType = '[object Function]';
|
12711
|
+
/* eslint no-invalid-this: 1 */
|
12688
12712
|
|
12689
|
-
|
12690
|
-
|
12691
|
-
|
12692
|
-
|
12693
|
-
arr[i] = a[i];
|
12694
|
-
}
|
12695
|
-
for (var j = 0; j < b.length; j += 1) {
|
12696
|
-
arr[j + a.length] = b[j];
|
12697
|
-
}
|
12713
|
+
var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
|
12714
|
+
var toStr = Object.prototype.toString;
|
12715
|
+
var max$1 = Math.max;
|
12716
|
+
var funcType = '[object Function]';
|
12698
12717
|
|
12699
|
-
|
12700
|
-
|
12718
|
+
var concatty = function concatty(a, b) {
|
12719
|
+
var arr = [];
|
12701
12720
|
|
12702
|
-
|
12703
|
-
|
12704
|
-
|
12705
|
-
|
12706
|
-
|
12707
|
-
|
12708
|
-
};
|
12721
|
+
for (var i = 0; i < a.length; i += 1) {
|
12722
|
+
arr[i] = a[i];
|
12723
|
+
}
|
12724
|
+
for (var j = 0; j < b.length; j += 1) {
|
12725
|
+
arr[j + a.length] = b[j];
|
12726
|
+
}
|
12709
12727
|
|
12710
|
-
|
12711
|
-
|
12712
|
-
for (var i = 0; i < arr.length; i += 1) {
|
12713
|
-
str += arr[i];
|
12714
|
-
if (i + 1 < arr.length) {
|
12715
|
-
str += joiner;
|
12716
|
-
}
|
12717
|
-
}
|
12718
|
-
return str;
|
12719
|
-
};
|
12728
|
+
return arr;
|
12729
|
+
};
|
12720
12730
|
|
12721
|
-
|
12722
|
-
|
12723
|
-
|
12724
|
-
|
12725
|
-
|
12726
|
-
|
12727
|
-
|
12728
|
-
var bound;
|
12729
|
-
var binder = function () {
|
12730
|
-
if (this instanceof bound) {
|
12731
|
-
var result = target.apply(
|
12732
|
-
this,
|
12733
|
-
concatty(args, arguments)
|
12734
|
-
);
|
12735
|
-
if (Object(result) === result) {
|
12736
|
-
return result;
|
12737
|
-
}
|
12738
|
-
return this;
|
12739
|
-
}
|
12740
|
-
return target.apply(
|
12741
|
-
that,
|
12742
|
-
concatty(args, arguments)
|
12743
|
-
);
|
12731
|
+
var slicy = function slicy(arrLike, offset) {
|
12732
|
+
var arr = [];
|
12733
|
+
for (var i = offset, j = 0; i < arrLike.length; i += 1, j += 1) {
|
12734
|
+
arr[j] = arrLike[i];
|
12735
|
+
}
|
12736
|
+
return arr;
|
12737
|
+
};
|
12744
12738
|
|
12745
|
-
|
12739
|
+
var joiny = function (arr, joiner) {
|
12740
|
+
var str = '';
|
12741
|
+
for (var i = 0; i < arr.length; i += 1) {
|
12742
|
+
str += arr[i];
|
12743
|
+
if (i + 1 < arr.length) {
|
12744
|
+
str += joiner;
|
12745
|
+
}
|
12746
|
+
}
|
12747
|
+
return str;
|
12748
|
+
};
|
12746
12749
|
|
12747
|
-
|
12748
|
-
|
12749
|
-
|
12750
|
-
|
12751
|
-
|
12750
|
+
var implementation$1 = function bind(that) {
|
12751
|
+
var target = this;
|
12752
|
+
if (typeof target !== 'function' || toStr.apply(target) !== funcType) {
|
12753
|
+
throw new TypeError(ERROR_MESSAGE + target);
|
12754
|
+
}
|
12755
|
+
var args = slicy(arguments, 1);
|
12756
|
+
|
12757
|
+
var bound;
|
12758
|
+
var binder = function () {
|
12759
|
+
if (this instanceof bound) {
|
12760
|
+
var result = target.apply(
|
12761
|
+
this,
|
12762
|
+
concatty(args, arguments)
|
12763
|
+
);
|
12764
|
+
if (Object(result) === result) {
|
12765
|
+
return result;
|
12766
|
+
}
|
12767
|
+
return this;
|
12768
|
+
}
|
12769
|
+
return target.apply(
|
12770
|
+
that,
|
12771
|
+
concatty(args, arguments)
|
12772
|
+
);
|
12752
12773
|
|
12753
|
-
|
12774
|
+
};
|
12754
12775
|
|
12755
|
-
|
12756
|
-
|
12757
|
-
|
12758
|
-
|
12759
|
-
|
12760
|
-
}
|
12776
|
+
var boundLength = max$1(0, target.length - args.length);
|
12777
|
+
var boundArgs = [];
|
12778
|
+
for (var i = 0; i < boundLength; i++) {
|
12779
|
+
boundArgs[i] = '$' + i;
|
12780
|
+
}
|
12761
12781
|
|
12762
|
-
|
12763
|
-
};
|
12764
|
-
return implementation;
|
12765
|
-
}
|
12782
|
+
bound = Function('binder', 'return function (' + joiny(boundArgs, ',') + '){ return binder.apply(this,arguments); }')(binder);
|
12766
12783
|
|
12767
|
-
|
12768
|
-
var
|
12784
|
+
if (target.prototype) {
|
12785
|
+
var Empty = function Empty() {};
|
12786
|
+
Empty.prototype = target.prototype;
|
12787
|
+
bound.prototype = new Empty();
|
12788
|
+
Empty.prototype = null;
|
12789
|
+
}
|
12769
12790
|
|
12770
|
-
|
12771
|
-
|
12772
|
-
hasRequiredFunctionBind = 1;
|
12791
|
+
return bound;
|
12792
|
+
};
|
12773
12793
|
|
12774
|
-
|
12794
|
+
var implementation = implementation$1;
|
12775
12795
|
|
12776
|
-
|
12777
|
-
return functionBind;
|
12778
|
-
}
|
12796
|
+
var functionBind = Function.prototype.bind || implementation;
|
12779
12797
|
|
12780
12798
|
var functionCall;
|
12781
12799
|
var hasRequiredFunctionCall;
|
@@ -12820,7 +12838,7 @@ function requireActualApply () {
|
|
12820
12838
|
if (hasRequiredActualApply) return actualApply;
|
12821
12839
|
hasRequiredActualApply = 1;
|
12822
12840
|
|
12823
|
-
var bind =
|
12841
|
+
var bind = functionBind;
|
12824
12842
|
|
12825
12843
|
var $apply = requireFunctionApply();
|
12826
12844
|
var $call = requireFunctionCall();
|
@@ -12838,7 +12856,7 @@ function requireCallBindApplyHelpers () {
|
|
12838
12856
|
if (hasRequiredCallBindApplyHelpers) return callBindApplyHelpers;
|
12839
12857
|
hasRequiredCallBindApplyHelpers = 1;
|
12840
12858
|
|
12841
|
-
var bind =
|
12859
|
+
var bind = functionBind;
|
12842
12860
|
var $TypeError = requireType();
|
12843
12861
|
|
12844
12862
|
var $call = requireFunctionCall();
|
@@ -12927,21 +12945,12 @@ function requireGetProto () {
|
|
12927
12945
|
return getProto$1;
|
12928
12946
|
}
|
12929
12947
|
|
12930
|
-
var
|
12931
|
-
var
|
12932
|
-
|
12933
|
-
function requireHasown () {
|
12934
|
-
if (hasRequiredHasown) return hasown;
|
12935
|
-
hasRequiredHasown = 1;
|
12948
|
+
var call = Function.prototype.call;
|
12949
|
+
var $hasOwn = Object.prototype.hasOwnProperty;
|
12950
|
+
var bind$1 = functionBind;
|
12936
12951
|
|
12937
|
-
|
12938
|
-
|
12939
|
-
var bind = requireFunctionBind();
|
12940
|
-
|
12941
|
-
/** @type {import('.')} */
|
12942
|
-
hasown = bind.call(call, $hasOwn);
|
12943
|
-
return hasown;
|
12944
|
-
}
|
12952
|
+
/** @type {import('.')} */
|
12953
|
+
var hasown = bind$1.call(call, $hasOwn);
|
12945
12954
|
|
12946
12955
|
var undefined$1;
|
12947
12956
|
|
@@ -12957,7 +12966,7 @@ var $URIError = uri;
|
|
12957
12966
|
|
12958
12967
|
var abs = abs$1;
|
12959
12968
|
var floor = floor$1;
|
12960
|
-
var max = max$
|
12969
|
+
var max = max$2;
|
12961
12970
|
var min = min$1;
|
12962
12971
|
var pow = pow$1;
|
12963
12972
|
var round = round$1;
|
@@ -13183,8 +13192,8 @@ var LEGACY_ALIASES = {
|
|
13183
13192
|
'%WeakSetPrototype%': ['WeakSet', 'prototype']
|
13184
13193
|
};
|
13185
13194
|
|
13186
|
-
var bind =
|
13187
|
-
var hasOwn$
|
13195
|
+
var bind = functionBind;
|
13196
|
+
var hasOwn$2 = hasown;
|
13188
13197
|
var $concat = bind.call($call, Array.prototype.concat);
|
13189
13198
|
var $spliceApply = bind.call($apply, Array.prototype.splice);
|
13190
13199
|
var $replace = bind.call($call, String.prototype.replace);
|
@@ -13213,12 +13222,12 @@ var stringToPath = function stringToPath(string) {
|
|
13213
13222
|
var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) {
|
13214
13223
|
var intrinsicName = name;
|
13215
13224
|
var alias;
|
13216
|
-
if (hasOwn$
|
13225
|
+
if (hasOwn$2(LEGACY_ALIASES, intrinsicName)) {
|
13217
13226
|
alias = LEGACY_ALIASES[intrinsicName];
|
13218
13227
|
intrinsicName = '%' + alias[0] + '%';
|
13219
13228
|
}
|
13220
13229
|
|
13221
|
-
if (hasOwn$
|
13230
|
+
if (hasOwn$2(INTRINSICS, intrinsicName)) {
|
13222
13231
|
var value = INTRINSICS[intrinsicName];
|
13223
13232
|
if (value === needsEval) {
|
13224
13233
|
value = doEval(intrinsicName);
|
@@ -13282,14 +13291,14 @@ var getIntrinsic = function GetIntrinsic(name, allowMissing) {
|
|
13282
13291
|
intrinsicBaseName += '.' + part;
|
13283
13292
|
intrinsicRealName = '%' + intrinsicBaseName + '%';
|
13284
13293
|
|
13285
|
-
if (hasOwn$
|
13294
|
+
if (hasOwn$2(INTRINSICS, intrinsicRealName)) {
|
13286
13295
|
value = INTRINSICS[intrinsicRealName];
|
13287
13296
|
} else if (value != null) {
|
13288
13297
|
if (!(part in value)) {
|
13289
13298
|
if (!allowMissing) {
|
13290
13299
|
throw new $TypeError$1('base intrinsic for ' + name + ' exists, but the property is not available.');
|
13291
13300
|
}
|
13292
|
-
return void
|
13301
|
+
return void undefined$1;
|
13293
13302
|
}
|
13294
13303
|
if ($gOPD && (i + 1) >= parts.length) {
|
13295
13304
|
var desc = $gOPD(value, part);
|
@@ -13308,7 +13317,7 @@ var getIntrinsic = function GetIntrinsic(name, allowMissing) {
|
|
13308
13317
|
value = value[part];
|
13309
13318
|
}
|
13310
13319
|
} else {
|
13311
|
-
isOwn = hasOwn$
|
13320
|
+
isOwn = hasOwn$2(value, part);
|
13312
13321
|
value = value[part];
|
13313
13322
|
}
|
13314
13323
|
|
@@ -13341,7 +13350,7 @@ var GetIntrinsic = getIntrinsic;
|
|
13341
13350
|
var $defineProperty = GetIntrinsic('%Object.defineProperty%', true);
|
13342
13351
|
|
13343
13352
|
var hasToStringTag = requireShams()();
|
13344
|
-
var hasOwn =
|
13353
|
+
var hasOwn$1 = hasown;
|
13345
13354
|
var $TypeError = requireType();
|
13346
13355
|
|
13347
13356
|
var toStringTag = hasToStringTag ? Symbol.toStringTag : null;
|
@@ -13356,7 +13365,7 @@ var esSetTostringtag = function setToStringTag(object, value) {
|
|
13356
13365
|
) {
|
13357
13366
|
throw new $TypeError('if provided, the `overrideIfSet` and `nonConfigurable` options must be booleans');
|
13358
13367
|
}
|
13359
|
-
if (toStringTag && (overrideIfSet || !hasOwn(object, toStringTag))) {
|
13368
|
+
if (toStringTag && (overrideIfSet || !hasOwn$1(object, toStringTag))) {
|
13360
13369
|
if ($defineProperty) {
|
13361
13370
|
$defineProperty(object, toStringTag, {
|
13362
13371
|
configurable: !nonConfigurable,
|
@@ -13371,11 +13380,9 @@ var esSetTostringtag = function setToStringTag(object, value) {
|
|
13371
13380
|
};
|
13372
13381
|
|
13373
13382
|
// populates missing values
|
13374
|
-
var populate$1 = function(dst, src) {
|
13375
|
-
|
13376
|
-
|
13377
|
-
{
|
13378
|
-
dst[prop] = dst[prop] || src[prop];
|
13383
|
+
var populate$1 = function (dst, src) {
|
13384
|
+
Object.keys(src).forEach(function (prop) {
|
13385
|
+
dst[prop] = dst[prop] || src[prop]; // eslint-disable-line no-param-reassign
|
13379
13386
|
});
|
13380
13387
|
|
13381
13388
|
return dst;
|
@@ -13389,24 +13396,20 @@ var https$1 = require$$4;
|
|
13389
13396
|
var parseUrl$2 = require$$0$1.parse;
|
13390
13397
|
var fs = require$$6;
|
13391
13398
|
var Stream = stream.Stream;
|
13399
|
+
var crypto = require$$8;
|
13392
13400
|
var mime = mimeTypes;
|
13393
13401
|
var asynckit = asynckit$1;
|
13394
13402
|
var setToStringTag = esSetTostringtag;
|
13403
|
+
var hasOwn = hasown;
|
13395
13404
|
var populate = populate$1;
|
13396
13405
|
|
13397
|
-
// Public API
|
13398
|
-
var form_data = FormData$1;
|
13399
|
-
|
13400
|
-
// make it a Stream
|
13401
|
-
util.inherits(FormData$1, CombinedStream);
|
13402
|
-
|
13403
13406
|
/**
|
13404
13407
|
* Create readable "multipart/form-data" streams.
|
13405
13408
|
* Can be used to submit forms
|
13406
13409
|
* and file uploads to other web applications.
|
13407
13410
|
*
|
13408
13411
|
* @constructor
|
13409
|
-
* @param {
|
13412
|
+
* @param {object} options - Properties to be added/overriden for FormData and CombinedStream
|
13410
13413
|
*/
|
13411
13414
|
function FormData$1(options) {
|
13412
13415
|
if (!(this instanceof FormData$1)) {
|
@@ -13419,35 +13422,39 @@ function FormData$1(options) {
|
|
13419
13422
|
|
13420
13423
|
CombinedStream.call(this);
|
13421
13424
|
|
13422
|
-
options = options || {};
|
13423
|
-
for (var option in options) {
|
13425
|
+
options = options || {}; // eslint-disable-line no-param-reassign
|
13426
|
+
for (var option in options) { // eslint-disable-line no-restricted-syntax
|
13424
13427
|
this[option] = options[option];
|
13425
13428
|
}
|
13426
13429
|
}
|
13427
13430
|
|
13431
|
+
// make it a Stream
|
13432
|
+
util.inherits(FormData$1, CombinedStream);
|
13433
|
+
|
13428
13434
|
FormData$1.LINE_BREAK = '\r\n';
|
13429
13435
|
FormData$1.DEFAULT_CONTENT_TYPE = 'application/octet-stream';
|
13430
13436
|
|
13431
|
-
FormData$1.prototype.append = function(field, value, options) {
|
13432
|
-
|
13433
|
-
options = options || {};
|
13437
|
+
FormData$1.prototype.append = function (field, value, options) {
|
13438
|
+
options = options || {}; // eslint-disable-line no-param-reassign
|
13434
13439
|
|
13435
13440
|
// allow filename as single option
|
13436
|
-
if (typeof options
|
13437
|
-
options = {filename: options};
|
13441
|
+
if (typeof options === 'string') {
|
13442
|
+
options = { filename: options }; // eslint-disable-line no-param-reassign
|
13438
13443
|
}
|
13439
13444
|
|
13440
13445
|
var append = CombinedStream.prototype.append.bind(this);
|
13441
13446
|
|
13442
13447
|
// all that streamy business can't handle numbers
|
13443
|
-
if (typeof value
|
13444
|
-
value =
|
13448
|
+
if (typeof value === 'number' || value == null) {
|
13449
|
+
value = String(value); // eslint-disable-line no-param-reassign
|
13445
13450
|
}
|
13446
13451
|
|
13447
13452
|
// https://github.com/felixge/node-form-data/issues/38
|
13448
13453
|
if (Array.isArray(value)) {
|
13449
|
-
|
13450
|
-
|
13454
|
+
/*
|
13455
|
+
* Please convert your array into string
|
13456
|
+
* the way web server expects it
|
13457
|
+
*/
|
13451
13458
|
this._error(new Error('Arrays are not supported.'));
|
13452
13459
|
return;
|
13453
13460
|
}
|
@@ -13463,15 +13470,17 @@ FormData$1.prototype.append = function(field, value, options) {
|
|
13463
13470
|
this._trackLength(header, value, options);
|
13464
13471
|
};
|
13465
13472
|
|
13466
|
-
FormData$1.prototype._trackLength = function(header, value, options) {
|
13473
|
+
FormData$1.prototype._trackLength = function (header, value, options) {
|
13467
13474
|
var valueLength = 0;
|
13468
13475
|
|
13469
|
-
|
13470
|
-
|
13471
|
-
|
13472
|
-
|
13476
|
+
/*
|
13477
|
+
* used w/ getLengthSync(), when length is known.
|
13478
|
+
* e.g. for streaming directly from a remote server,
|
13479
|
+
* w/ a known file a size, and not wanting to wait for
|
13480
|
+
* incoming file to finish to get its size.
|
13481
|
+
*/
|
13473
13482
|
if (options.knownLength != null) {
|
13474
|
-
valueLength +=
|
13483
|
+
valueLength += Number(options.knownLength);
|
13475
13484
|
} else if (Buffer.isBuffer(value)) {
|
13476
13485
|
valueLength = value.length;
|
13477
13486
|
} else if (typeof value === 'string') {
|
@@ -13481,12 +13490,10 @@ FormData$1.prototype._trackLength = function(header, value, options) {
|
|
13481
13490
|
this._valueLength += valueLength;
|
13482
13491
|
|
13483
13492
|
// @check why add CRLF? does this account for custom/multiple CRLFs?
|
13484
|
-
this._overheadLength +=
|
13485
|
-
Buffer.byteLength(header) +
|
13486
|
-
FormData$1.LINE_BREAK.length;
|
13493
|
+
this._overheadLength += Buffer.byteLength(header) + FormData$1.LINE_BREAK.length;
|
13487
13494
|
|
13488
13495
|
// empty or either doesn't have path or not an http response or not a stream
|
13489
|
-
if (!value || (
|
13496
|
+
if (!value || (!value.path && !(value.readable && hasOwn(value, 'httpVersion')) && !(value instanceof Stream))) {
|
13490
13497
|
return;
|
13491
13498
|
}
|
13492
13499
|
|
@@ -13496,9 +13503,8 @@ FormData$1.prototype._trackLength = function(header, value, options) {
|
|
13496
13503
|
}
|
13497
13504
|
};
|
13498
13505
|
|
13499
|
-
FormData$1.prototype._lengthRetriever = function(value, callback) {
|
13500
|
-
if (
|
13501
|
-
|
13506
|
+
FormData$1.prototype._lengthRetriever = function (value, callback) {
|
13507
|
+
if (hasOwn(value, 'fd')) {
|
13502
13508
|
// take read range into a account
|
13503
13509
|
// `end` = Infinity –> read file till the end
|
13504
13510
|
//
|
@@ -13507,54 +13513,52 @@ FormData$1.prototype._lengthRetriever = function(value, callback) {
|
|
13507
13513
|
// Fix it when node fixes it.
|
13508
13514
|
// https://github.com/joyent/node/issues/7819
|
13509
13515
|
if (value.end != undefined && value.end != Infinity && value.start != undefined) {
|
13510
|
-
|
13511
13516
|
// when end specified
|
13512
13517
|
// no need to calculate range
|
13513
13518
|
// inclusive, starts with 0
|
13514
|
-
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
13519
|
+
callback(null, value.end + 1 - (value.start ? value.start : 0)); // eslint-disable-line callback-return
|
13515
13520
|
|
13516
|
-
|
13521
|
+
// not that fast snoopy
|
13517
13522
|
} else {
|
13518
13523
|
// still need to fetch file size from fs
|
13519
|
-
fs.stat(value.path, function(err, stat) {
|
13520
|
-
|
13521
|
-
var fileSize;
|
13522
|
-
|
13524
|
+
fs.stat(value.path, function (err, stat) {
|
13523
13525
|
if (err) {
|
13524
13526
|
callback(err);
|
13525
13527
|
return;
|
13526
13528
|
}
|
13527
13529
|
|
13528
13530
|
// update final size based on the range options
|
13529
|
-
fileSize = stat.size - (value.start ? value.start : 0);
|
13531
|
+
var fileSize = stat.size - (value.start ? value.start : 0);
|
13530
13532
|
callback(null, fileSize);
|
13531
13533
|
});
|
13532
13534
|
}
|
13533
13535
|
|
13534
|
-
|
13535
|
-
} else if (
|
13536
|
-
callback(null,
|
13536
|
+
// or http response
|
13537
|
+
} else if (hasOwn(value, 'httpVersion')) {
|
13538
|
+
callback(null, Number(value.headers['content-length'])); // eslint-disable-line callback-return
|
13537
13539
|
|
13538
|
-
|
13539
|
-
} else if (
|
13540
|
+
// or request stream http://github.com/mikeal/request
|
13541
|
+
} else if (hasOwn(value, 'httpModule')) {
|
13540
13542
|
// wait till response come back
|
13541
|
-
value.on('response', function(response) {
|
13543
|
+
value.on('response', function (response) {
|
13542
13544
|
value.pause();
|
13543
|
-
callback(null,
|
13545
|
+
callback(null, Number(response.headers['content-length']));
|
13544
13546
|
});
|
13545
13547
|
value.resume();
|
13546
13548
|
|
13547
|
-
|
13549
|
+
// something else
|
13548
13550
|
} else {
|
13549
|
-
callback('Unknown stream');
|
13551
|
+
callback('Unknown stream'); // eslint-disable-line callback-return
|
13550
13552
|
}
|
13551
13553
|
};
|
13552
13554
|
|
13553
|
-
FormData$1.prototype._multiPartHeader = function(field, value, options) {
|
13554
|
-
|
13555
|
-
|
13556
|
-
|
13557
|
-
|
13555
|
+
FormData$1.prototype._multiPartHeader = function (field, value, options) {
|
13556
|
+
/*
|
13557
|
+
* custom header specified (as string)?
|
13558
|
+
* it becomes responsible for boundary
|
13559
|
+
* (e.g. to handle extra CRLFs on .NET servers)
|
13560
|
+
*/
|
13561
|
+
if (typeof options.header === 'string') {
|
13558
13562
|
return options.header;
|
13559
13563
|
}
|
13560
13564
|
|
@@ -13562,7 +13566,7 @@ FormData$1.prototype._multiPartHeader = function(field, value, options) {
|
|
13562
13566
|
var contentType = this._getContentType(value, options);
|
13563
13567
|
|
13564
13568
|
var contents = '';
|
13565
|
-
var headers
|
13569
|
+
var headers = {
|
13566
13570
|
// add custom disposition as third element or keep it two elements if not
|
13567
13571
|
'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || []),
|
13568
13572
|
// if no content type. allow it to be empty array
|
@@ -13570,18 +13574,18 @@ FormData$1.prototype._multiPartHeader = function(field, value, options) {
|
|
13570
13574
|
};
|
13571
13575
|
|
13572
13576
|
// allow custom headers.
|
13573
|
-
if (typeof options.header
|
13577
|
+
if (typeof options.header === 'object') {
|
13574
13578
|
populate(headers, options.header);
|
13575
13579
|
}
|
13576
13580
|
|
13577
13581
|
var header;
|
13578
|
-
for (var prop in headers) {
|
13579
|
-
if (
|
13582
|
+
for (var prop in headers) { // eslint-disable-line no-restricted-syntax
|
13583
|
+
if (hasOwn(headers, prop)) {
|
13580
13584
|
header = headers[prop];
|
13581
13585
|
|
13582
13586
|
// skip nullish headers.
|
13583
13587
|
if (header == null) {
|
13584
|
-
continue;
|
13588
|
+
continue; // eslint-disable-line no-restricted-syntax, no-continue
|
13585
13589
|
}
|
13586
13590
|
|
13587
13591
|
// convert all headers to arrays.
|
@@ -13599,49 +13603,45 @@ FormData$1.prototype._multiPartHeader = function(field, value, options) {
|
|
13599
13603
|
return '--' + this.getBoundary() + FormData$1.LINE_BREAK + contents + FormData$1.LINE_BREAK;
|
13600
13604
|
};
|
13601
13605
|
|
13602
|
-
FormData$1.prototype._getContentDisposition = function(value, options) {
|
13603
|
-
|
13604
|
-
var filename
|
13605
|
-
, contentDisposition
|
13606
|
-
;
|
13606
|
+
FormData$1.prototype._getContentDisposition = function (value, options) { // eslint-disable-line consistent-return
|
13607
|
+
var filename;
|
13607
13608
|
|
13608
13609
|
if (typeof options.filepath === 'string') {
|
13609
13610
|
// custom filepath for relative paths
|
13610
13611
|
filename = path.normalize(options.filepath).replace(/\\/g, '/');
|
13611
|
-
} else if (options.filename || value.name || value.path) {
|
13612
|
-
|
13613
|
-
|
13614
|
-
|
13615
|
-
|
13616
|
-
|
13612
|
+
} else if (options.filename || (value && (value.name || value.path))) {
|
13613
|
+
/*
|
13614
|
+
* custom filename take precedence
|
13615
|
+
* formidable and the browser add a name property
|
13616
|
+
* fs- and request- streams have path property
|
13617
|
+
*/
|
13618
|
+
filename = path.basename(options.filename || (value && (value.name || value.path)));
|
13619
|
+
} else if (value && value.readable && hasOwn(value, 'httpVersion')) {
|
13617
13620
|
// or try http response
|
13618
13621
|
filename = path.basename(value.client._httpMessage.path || '');
|
13619
13622
|
}
|
13620
13623
|
|
13621
13624
|
if (filename) {
|
13622
|
-
|
13625
|
+
return 'filename="' + filename + '"';
|
13623
13626
|
}
|
13624
|
-
|
13625
|
-
return contentDisposition;
|
13626
13627
|
};
|
13627
13628
|
|
13628
|
-
FormData$1.prototype._getContentType = function(value, options) {
|
13629
|
-
|
13629
|
+
FormData$1.prototype._getContentType = function (value, options) {
|
13630
13630
|
// use custom content-type above all
|
13631
13631
|
var contentType = options.contentType;
|
13632
13632
|
|
13633
13633
|
// or try `name` from formidable, browser
|
13634
|
-
if (!contentType && value.name) {
|
13634
|
+
if (!contentType && value && value.name) {
|
13635
13635
|
contentType = mime.lookup(value.name);
|
13636
13636
|
}
|
13637
13637
|
|
13638
13638
|
// or try `path` from fs-, request- streams
|
13639
|
-
if (!contentType && value.path) {
|
13639
|
+
if (!contentType && value && value.path) {
|
13640
13640
|
contentType = mime.lookup(value.path);
|
13641
13641
|
}
|
13642
13642
|
|
13643
13643
|
// or if it's http-reponse
|
13644
|
-
if (!contentType && value.readable &&
|
13644
|
+
if (!contentType && value && value.readable && hasOwn(value, 'httpVersion')) {
|
13645
13645
|
contentType = value.headers['content-type'];
|
13646
13646
|
}
|
13647
13647
|
|
@@ -13651,18 +13651,18 @@ FormData$1.prototype._getContentType = function(value, options) {
|
|
13651
13651
|
}
|
13652
13652
|
|
13653
13653
|
// fallback to the default content type if `value` is not simple value
|
13654
|
-
if (!contentType && typeof value
|
13654
|
+
if (!contentType && value && typeof value === 'object') {
|
13655
13655
|
contentType = FormData$1.DEFAULT_CONTENT_TYPE;
|
13656
13656
|
}
|
13657
13657
|
|
13658
13658
|
return contentType;
|
13659
13659
|
};
|
13660
13660
|
|
13661
|
-
FormData$1.prototype._multiPartFooter = function() {
|
13662
|
-
return function(next) {
|
13661
|
+
FormData$1.prototype._multiPartFooter = function () {
|
13662
|
+
return function (next) {
|
13663
13663
|
var footer = FormData$1.LINE_BREAK;
|
13664
13664
|
|
13665
|
-
var lastPart =
|
13665
|
+
var lastPart = this._streams.length === 0;
|
13666
13666
|
if (lastPart) {
|
13667
13667
|
footer += this._lastBoundary();
|
13668
13668
|
}
|
@@ -13671,18 +13671,18 @@ FormData$1.prototype._multiPartFooter = function() {
|
|
13671
13671
|
}.bind(this);
|
13672
13672
|
};
|
13673
13673
|
|
13674
|
-
FormData$1.prototype._lastBoundary = function() {
|
13674
|
+
FormData$1.prototype._lastBoundary = function () {
|
13675
13675
|
return '--' + this.getBoundary() + '--' + FormData$1.LINE_BREAK;
|
13676
13676
|
};
|
13677
13677
|
|
13678
|
-
FormData$1.prototype.getHeaders = function(userHeaders) {
|
13678
|
+
FormData$1.prototype.getHeaders = function (userHeaders) {
|
13679
13679
|
var header;
|
13680
13680
|
var formHeaders = {
|
13681
13681
|
'content-type': 'multipart/form-data; boundary=' + this.getBoundary()
|
13682
13682
|
};
|
13683
13683
|
|
13684
|
-
for (header in userHeaders) {
|
13685
|
-
if (
|
13684
|
+
for (header in userHeaders) { // eslint-disable-line no-restricted-syntax
|
13685
|
+
if (hasOwn(userHeaders, header)) {
|
13686
13686
|
formHeaders[header.toLowerCase()] = userHeaders[header];
|
13687
13687
|
}
|
13688
13688
|
}
|
@@ -13690,11 +13690,14 @@ FormData$1.prototype.getHeaders = function(userHeaders) {
|
|
13690
13690
|
return formHeaders;
|
13691
13691
|
};
|
13692
13692
|
|
13693
|
-
FormData$1.prototype.setBoundary = function(boundary) {
|
13693
|
+
FormData$1.prototype.setBoundary = function (boundary) {
|
13694
|
+
if (typeof boundary !== 'string') {
|
13695
|
+
throw new TypeError('FormData boundary must be a string');
|
13696
|
+
}
|
13694
13697
|
this._boundary = boundary;
|
13695
13698
|
};
|
13696
13699
|
|
13697
|
-
FormData$1.prototype.getBoundary = function() {
|
13700
|
+
FormData$1.prototype.getBoundary = function () {
|
13698
13701
|
if (!this._boundary) {
|
13699
13702
|
this._generateBoundary();
|
13700
13703
|
}
|
@@ -13702,60 +13705,55 @@ FormData$1.prototype.getBoundary = function() {
|
|
13702
13705
|
return this._boundary;
|
13703
13706
|
};
|
13704
13707
|
|
13705
|
-
FormData$1.prototype.getBuffer = function() {
|
13706
|
-
var dataBuffer = new Buffer.alloc(0);
|
13708
|
+
FormData$1.prototype.getBuffer = function () {
|
13709
|
+
var dataBuffer = new Buffer.alloc(0); // eslint-disable-line new-cap
|
13707
13710
|
var boundary = this.getBoundary();
|
13708
13711
|
|
13709
13712
|
// Create the form content. Add Line breaks to the end of data.
|
13710
13713
|
for (var i = 0, len = this._streams.length; i < len; i++) {
|
13711
13714
|
if (typeof this._streams[i] !== 'function') {
|
13712
|
-
|
13713
13715
|
// Add content to the buffer.
|
13714
|
-
if(Buffer.isBuffer(this._streams[i])) {
|
13715
|
-
dataBuffer = Buffer.concat(
|
13716
|
-
}else {
|
13717
|
-
dataBuffer = Buffer.concat(
|
13716
|
+
if (Buffer.isBuffer(this._streams[i])) {
|
13717
|
+
dataBuffer = Buffer.concat([dataBuffer, this._streams[i]]);
|
13718
|
+
} else {
|
13719
|
+
dataBuffer = Buffer.concat([dataBuffer, Buffer.from(this._streams[i])]);
|
13718
13720
|
}
|
13719
13721
|
|
13720
13722
|
// Add break after content.
|
13721
|
-
if (typeof this._streams[i] !== 'string' || this._streams[i].substring(
|
13722
|
-
dataBuffer = Buffer.concat(
|
13723
|
+
if (typeof this._streams[i] !== 'string' || this._streams[i].substring(2, boundary.length + 2) !== boundary) {
|
13724
|
+
dataBuffer = Buffer.concat([dataBuffer, Buffer.from(FormData$1.LINE_BREAK)]);
|
13723
13725
|
}
|
13724
13726
|
}
|
13725
13727
|
}
|
13726
13728
|
|
13727
13729
|
// Add the footer and return the Buffer object.
|
13728
|
-
return Buffer.concat(
|
13730
|
+
return Buffer.concat([dataBuffer, Buffer.from(this._lastBoundary())]);
|
13729
13731
|
};
|
13730
13732
|
|
13731
|
-
FormData$1.prototype._generateBoundary = function() {
|
13733
|
+
FormData$1.prototype._generateBoundary = function () {
|
13732
13734
|
// This generates a 50 character boundary similar to those used by Firefox.
|
13733
|
-
// They are optimized for boyer-moore parsing.
|
13734
|
-
var boundary = '--------------------------';
|
13735
|
-
for (var i = 0; i < 24; i++) {
|
13736
|
-
boundary += Math.floor(Math.random() * 10).toString(16);
|
13737
|
-
}
|
13738
13735
|
|
13739
|
-
|
13736
|
+
// They are optimized for boyer-moore parsing.
|
13737
|
+
this._boundary = '--------------------------' + crypto.randomBytes(12).toString('hex');
|
13740
13738
|
};
|
13741
13739
|
|
13742
13740
|
// Note: getLengthSync DOESN'T calculate streams length
|
13743
|
-
// As workaround one can calculate file size manually
|
13744
|
-
|
13745
|
-
FormData$1.prototype.getLengthSync = function() {
|
13741
|
+
// As workaround one can calculate file size manually and add it as knownLength option
|
13742
|
+
FormData$1.prototype.getLengthSync = function () {
|
13746
13743
|
var knownLength = this._overheadLength + this._valueLength;
|
13747
13744
|
|
13748
|
-
// Don't get confused, there are 3 "internal" streams for each keyval pair
|
13749
|
-
// so it basically checks if there is any value added to the form
|
13745
|
+
// Don't get confused, there are 3 "internal" streams for each keyval pair so it basically checks if there is any value added to the form
|
13750
13746
|
if (this._streams.length) {
|
13751
13747
|
knownLength += this._lastBoundary().length;
|
13752
13748
|
}
|
13753
13749
|
|
13754
13750
|
// https://github.com/form-data/form-data/issues/40
|
13755
13751
|
if (!this.hasKnownLength()) {
|
13756
|
-
|
13757
|
-
|
13758
|
-
|
13752
|
+
/*
|
13753
|
+
* Some async length retrievers are present
|
13754
|
+
* therefore synchronous length calculation is false.
|
13755
|
+
* Please use getLength(callback) to get proper length
|
13756
|
+
*/
|
13759
13757
|
this._error(new Error('Cannot calculate proper length in synchronous way.'));
|
13760
13758
|
}
|
13761
13759
|
|
@@ -13765,7 +13763,7 @@ FormData$1.prototype.getLengthSync = function() {
|
|
13765
13763
|
// Public API to check if length of added values is known
|
13766
13764
|
// https://github.com/form-data/form-data/issues/196
|
13767
13765
|
// https://github.com/form-data/form-data/issues/262
|
13768
|
-
FormData$1.prototype.hasKnownLength = function() {
|
13766
|
+
FormData$1.prototype.hasKnownLength = function () {
|
13769
13767
|
var hasKnownLength = true;
|
13770
13768
|
|
13771
13769
|
if (this._valuesToMeasure.length) {
|
@@ -13775,7 +13773,7 @@ FormData$1.prototype.hasKnownLength = function() {
|
|
13775
13773
|
return hasKnownLength;
|
13776
13774
|
};
|
13777
13775
|
|
13778
|
-
FormData$1.prototype.getLength = function(cb) {
|
13776
|
+
FormData$1.prototype.getLength = function (cb) {
|
13779
13777
|
var knownLength = this._overheadLength + this._valueLength;
|
13780
13778
|
|
13781
13779
|
if (this._streams.length) {
|
@@ -13787,13 +13785,13 @@ FormData$1.prototype.getLength = function(cb) {
|
|
13787
13785
|
return;
|
13788
13786
|
}
|
13789
13787
|
|
13790
|
-
asynckit.parallel(this._valuesToMeasure, this._lengthRetriever, function(err, values) {
|
13788
|
+
asynckit.parallel(this._valuesToMeasure, this._lengthRetriever, function (err, values) {
|
13791
13789
|
if (err) {
|
13792
13790
|
cb(err);
|
13793
13791
|
return;
|
13794
13792
|
}
|
13795
13793
|
|
13796
|
-
values.forEach(function(length) {
|
13794
|
+
values.forEach(function (length) {
|
13797
13795
|
knownLength += length;
|
13798
13796
|
});
|
13799
13797
|
|
@@ -13801,31 +13799,26 @@ FormData$1.prototype.getLength = function(cb) {
|
|
13801
13799
|
});
|
13802
13800
|
};
|
13803
13801
|
|
13804
|
-
FormData$1.prototype.submit = function(params, cb) {
|
13805
|
-
var request
|
13806
|
-
|
13807
|
-
|
13808
|
-
;
|
13809
|
-
|
13810
|
-
// parse provided url if it's string
|
13811
|
-
// or treat it as options object
|
13812
|
-
if (typeof params == 'string') {
|
13802
|
+
FormData$1.prototype.submit = function (params, cb) {
|
13803
|
+
var request;
|
13804
|
+
var options;
|
13805
|
+
var defaults = { method: 'post' };
|
13813
13806
|
|
13814
|
-
|
13807
|
+
// parse provided url if it's string or treat it as options object
|
13808
|
+
if (typeof params === 'string') {
|
13809
|
+
params = parseUrl$2(params); // eslint-disable-line no-param-reassign
|
13810
|
+
/* eslint sort-keys: 0 */
|
13815
13811
|
options = populate({
|
13816
13812
|
port: params.port,
|
13817
13813
|
path: params.pathname,
|
13818
13814
|
host: params.hostname,
|
13819
13815
|
protocol: params.protocol
|
13820
13816
|
}, defaults);
|
13821
|
-
|
13822
|
-
// use custom params
|
13823
|
-
} else {
|
13824
|
-
|
13817
|
+
} else { // use custom params
|
13825
13818
|
options = populate(params, defaults);
|
13826
13819
|
// if no port provided use default one
|
13827
13820
|
if (!options.port) {
|
13828
|
-
options.port = options.protocol
|
13821
|
+
options.port = options.protocol === 'https:' ? 443 : 80;
|
13829
13822
|
}
|
13830
13823
|
}
|
13831
13824
|
|
@@ -13833,14 +13826,14 @@ FormData$1.prototype.submit = function(params, cb) {
|
|
13833
13826
|
options.headers = this.getHeaders(params.headers);
|
13834
13827
|
|
13835
13828
|
// https if specified, fallback to http in any other case
|
13836
|
-
if (options.protocol
|
13829
|
+
if (options.protocol === 'https:') {
|
13837
13830
|
request = https$1.request(options);
|
13838
13831
|
} else {
|
13839
13832
|
request = http$1.request(options);
|
13840
13833
|
}
|
13841
13834
|
|
13842
13835
|
// get content length and fire away
|
13843
|
-
this.getLength(function(err, length) {
|
13836
|
+
this.getLength(function (err, length) {
|
13844
13837
|
if (err && err !== 'Unknown stream') {
|
13845
13838
|
this._error(err);
|
13846
13839
|
return;
|
@@ -13859,7 +13852,7 @@ FormData$1.prototype.submit = function(params, cb) {
|
|
13859
13852
|
request.removeListener('error', callback);
|
13860
13853
|
request.removeListener('response', onResponse);
|
13861
13854
|
|
13862
|
-
return cb.call(this, error, responce);
|
13855
|
+
return cb.call(this, error, responce); // eslint-disable-line no-invalid-this
|
13863
13856
|
};
|
13864
13857
|
|
13865
13858
|
onResponse = callback.bind(this, null);
|
@@ -13872,7 +13865,7 @@ FormData$1.prototype.submit = function(params, cb) {
|
|
13872
13865
|
return request;
|
13873
13866
|
};
|
13874
13867
|
|
13875
|
-
FormData$1.prototype._error = function(err) {
|
13868
|
+
FormData$1.prototype._error = function (err) {
|
13876
13869
|
if (!this.error) {
|
13877
13870
|
this.error = err;
|
13878
13871
|
this.pause();
|
@@ -13885,6 +13878,9 @@ FormData$1.prototype.toString = function () {
|
|
13885
13878
|
};
|
13886
13879
|
setToStringTag(FormData$1, 'FormData');
|
13887
13880
|
|
13881
|
+
// Public API
|
13882
|
+
var form_data = FormData$1;
|
13883
|
+
|
13888
13884
|
var FormData$2 = /*@__PURE__*/getDefaultExportFromCjs(form_data);
|
13889
13885
|
|
13890
13886
|
/**
|
@@ -14002,6 +13998,10 @@ function toFormData$1(obj, formData, options) {
|
|
14002
13998
|
return value.toISOString();
|
14003
13999
|
}
|
14004
14000
|
|
14001
|
+
if (utils$1.isBoolean(value)) {
|
14002
|
+
return value.toString();
|
14003
|
+
}
|
14004
|
+
|
14005
14005
|
if (!useBlob && utils$1.isBlob(value)) {
|
14006
14006
|
throw new AxiosError$1('Blob is not supported. Use a Buffer instead.');
|
14007
14007
|
}
|
@@ -14304,7 +14304,7 @@ const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {
|
|
14304
14304
|
let str = '';
|
14305
14305
|
const {length} = alphabet;
|
14306
14306
|
const randomValues = new Uint32Array(size);
|
14307
|
-
|
14307
|
+
require$$8.randomFillSync(randomValues);
|
14308
14308
|
for (let i = 0; i < size; i++) {
|
14309
14309
|
str += alphabet[randomValues[i] % length];
|
14310
14310
|
}
|
@@ -14384,7 +14384,7 @@ var platform = {
|
|
14384
14384
|
};
|
14385
14385
|
|
14386
14386
|
function toURLEncodedForm(data, options) {
|
14387
|
-
return toFormData$1(data, new platform.classes.URLSearchParams(),
|
14387
|
+
return toFormData$1(data, new platform.classes.URLSearchParams(), {
|
14388
14388
|
visitor: function(value, key, path, helpers) {
|
14389
14389
|
if (platform.isNode && utils$1.isBuffer(value)) {
|
14390
14390
|
this.append(key, value.toString('base64'));
|
@@ -14392,8 +14392,9 @@ function toURLEncodedForm(data, options) {
|
|
14392
14392
|
}
|
14393
14393
|
|
14394
14394
|
return helpers.defaultVisitor.apply(this, arguments);
|
14395
|
-
}
|
14396
|
-
|
14395
|
+
},
|
14396
|
+
...options
|
14397
|
+
});
|
14397
14398
|
}
|
14398
14399
|
|
14399
14400
|
/**
|
@@ -15929,7 +15930,7 @@ followRedirects$1.exports.wrap = wrap;
|
|
15929
15930
|
var followRedirectsExports = followRedirects$1.exports;
|
15930
15931
|
var followRedirects = /*@__PURE__*/getDefaultExportFromCjs(followRedirectsExports);
|
15931
15932
|
|
15932
|
-
const VERSION$1 = "1.
|
15933
|
+
const VERSION$1 = "1.11.0";
|
15933
15934
|
|
15934
15935
|
function parseProtocol(url) {
|
15935
15936
|
const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url);
|
@@ -16347,7 +16348,7 @@ function throttle(fn, freq) {
|
|
16347
16348
|
clearTimeout(timer);
|
16348
16349
|
timer = null;
|
16349
16350
|
}
|
16350
|
-
fn
|
16351
|
+
fn(...args);
|
16351
16352
|
};
|
16352
16353
|
|
16353
16354
|
const throttled = (...args) => {
|
@@ -17221,7 +17222,7 @@ function mergeConfig$1(config1, config2) {
|
|
17221
17222
|
headers: (a, b , prop) => mergeDeepProperties(headersToObject(a), headersToObject(b),prop, true)
|
17222
17223
|
};
|
17223
17224
|
|
17224
|
-
utils$1.forEach(Object.keys(
|
17225
|
+
utils$1.forEach(Object.keys({...config1, ...config2}), function computeConfigValue(prop) {
|
17225
17226
|
const merge = mergeMap[prop] || mergeDeepProperties;
|
17226
17227
|
const configValue = merge(config1[prop], config2[prop], prop);
|
17227
17228
|
(utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
|
@@ -17754,7 +17755,7 @@ var fetchAdapter = isFetchSupported && (async (config) => {
|
|
17754
17755
|
credentials: isCredentialsSupported ? withCredentials : undefined
|
17755
17756
|
});
|
17756
17757
|
|
17757
|
-
let response = await fetch(request);
|
17758
|
+
let response = await fetch(request, fetchOptions);
|
17758
17759
|
|
17759
17760
|
const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response');
|
17760
17761
|
|
@@ -18197,8 +18198,8 @@ let Axios$1 = class Axios {
|
|
18197
18198
|
|
18198
18199
|
if (!synchronousRequestInterceptors) {
|
18199
18200
|
const chain = [dispatchRequest.bind(this), undefined];
|
18200
|
-
chain.unshift
|
18201
|
-
chain.push
|
18201
|
+
chain.unshift(...requestInterceptorChain);
|
18202
|
+
chain.push(...responseInterceptorChain);
|
18202
18203
|
len = chain.length;
|
18203
18204
|
|
18204
18205
|
promise = Promise.resolve(config);
|
@@ -18530,7 +18531,7 @@ Object.entries(HttpStatusCode$1).forEach(([key, value]) => {
|
|
18530
18531
|
*/
|
18531
18532
|
function createInstance(defaultConfig) {
|
18532
18533
|
const context = new Axios$1(defaultConfig);
|
18533
|
-
const instance = bind$
|
18534
|
+
const instance = bind$2(Axios$1.prototype.request, context);
|
18534
18535
|
|
18535
18536
|
// Copy axios.prototype to instance
|
18536
18537
|
utils$1.extend(instance, Axios$1.prototype, context, {allOwnKeys: true});
|
@@ -18769,25 +18770,21 @@ async function createWeeklyReportLegacy(args) {
|
|
18769
18770
|
if (farm.carbonCreditsProduced > 0 &&
|
18770
18771
|
usdgWeight <= 0 &&
|
18771
18772
|
rewardSplit.usdgSplitPercent > 0) {
|
18772
|
-
console.log(farm.carbonCreditsProduced, usdgWeight, rewardSplit.usdgSplitPercent);
|
18773
18773
|
throw new Error("USDG weight is less than 0 and carbon credits produced is greater than 0");
|
18774
18774
|
}
|
18775
18775
|
if (farm.weeklyPayment > 0 &&
|
18776
18776
|
glowWeight <= 0 &&
|
18777
18777
|
rewardSplit.glowSplitPercent > 0) {
|
18778
|
-
console.log(farm.weeklyPayment, glowWeight, rewardSplit.glowSplitPercent);
|
18779
18778
|
throw new Error("Glow weight is less than 0 and weekly payment is greater than 0");
|
18780
18779
|
}
|
18781
18780
|
if (farm.carbonCreditsProduced > 0 &&
|
18782
18781
|
usdgWeight <= 0 &&
|
18783
18782
|
rewardSplit.usdgSplitPercent > 0) {
|
18784
|
-
console.log(farm.carbonCreditsProduced, usdgWeight.toString(), rewardSplit.usdgSplitPercent);
|
18785
18783
|
throw new Error(`USDG weight is less than or equal to 0 and carbon credits produced is greater than 0 for farm ${farm.shortId}`);
|
18786
18784
|
}
|
18787
18785
|
if (farm.weeklyPayment > 0 &&
|
18788
18786
|
glowWeight <= 0 &&
|
18789
18787
|
rewardSplit.glowSplitPercent > 0) {
|
18790
|
-
console.log(farm.weeklyPayment, glowWeight.toString(), rewardSplit.glowSplitPercent);
|
18791
18788
|
throw new Error(`Glow weight is less than or equal to 0 and weekly payment is greater than 0 for farm ${farm.shortId}`);
|
18792
18789
|
}
|
18793
18790
|
addValueToMapLegacy(rewardSplit.walletAddress, value, mapLegacy);
|
@@ -18896,30 +18893,85 @@ async function createWeeklyReportLegacy(args) {
|
|
18896
18893
|
}
|
18897
18894
|
async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
18898
18895
|
const map = new Map();
|
18896
|
+
// Fetch active farms for the week (source of truth) and audits for the week.
|
18899
18897
|
const [apiResponse, auditsRes] = await Promise.all([
|
18900
18898
|
fetchFarmsForWeek(week, gcaUrls, apiUrl),
|
18901
18899
|
axios.get(`${HUB_URL}/api/audits?omitDocuments=true&weekNumber=${week}`),
|
18902
18900
|
]);
|
18903
|
-
const farms = apiResponse.filteredFarms;
|
18904
|
-
const audits = auditsRes.data;
|
18901
|
+
const farms = apiResponse.filteredFarms; // List of farms active this week.
|
18902
|
+
const audits = auditsRes.data; // Audits potentially containing adjusted credits.
|
18905
18903
|
const rawData = apiResponse.rawData;
|
18904
|
+
// Map to store the final adjusted credit (as bigint) for each active farm shortId.
|
18906
18905
|
const shortIdToAdjustedCredit = new Map();
|
18906
|
+
// Set to track shortIds that have been assigned a credit from a valid audit to prevent duplicates.
|
18907
|
+
const processedAuditShortIds = new Set();
|
18908
|
+
// Set of shortIds from the active farms list for quick lookup.
|
18909
|
+
const farmShortIds = new Set(farms.map((f) => String(f.shortId)));
|
18910
|
+
// Process each audit to extract adjusted credit values for active farms.
|
18907
18911
|
for (const audit of audits) {
|
18908
18912
|
const activeShortIds = audit.activeShortIds ?? [];
|
18909
18913
|
const adjustedCredit = audit.summary?.carbonFootprintAndProduction?.adjustedWeeklyCarbonCredit?.trim();
|
18914
|
+
// Basic validation: Ensure the audit has a valid numeric credit and lists associated shortIds.
|
18910
18915
|
if (!adjustedCredit || !NUMERIC_REGEX.test(adjustedCredit))
|
18911
18916
|
throw new Error(`Invalid adjustedWeeklyCarbonCredit for audit ${audit.id}`);
|
18912
18917
|
if (activeShortIds.length === 0)
|
18913
|
-
throw new Error(`
|
18914
|
-
|
18918
|
+
throw new Error(`Audit ${audit.id} has empty activeShortIds`);
|
18919
|
+
// Separate the shortIds listed in the audit into those that are active this week and those that are not.
|
18920
|
+
const auditActiveFarmSids = [];
|
18921
|
+
const auditInactiveFarmSids = [];
|
18922
|
+
for (const sid of activeShortIds) {
|
18923
|
+
const sidString = String(sid);
|
18924
|
+
if (farmShortIds.has(sidString)) {
|
18925
|
+
auditActiveFarmSids.push(sidString);
|
18926
|
+
}
|
18927
|
+
else {
|
18928
|
+
auditInactiveFarmSids.push(sidString);
|
18929
|
+
}
|
18930
|
+
}
|
18931
|
+
// --- Audit Validity Checks ---
|
18932
|
+
// Data Integrity Check: An audit for credit distribution should not mix active and inactive farms for the current week.
|
18933
|
+
if (auditActiveFarmSids.length > 0 && auditInactiveFarmSids.length > 0) {
|
18934
|
+
throw new Error(`Audit ${audit.id} for week ${week} contains a mix of active farms (${auditActiveFarmSids.join(", ")}) and inactive farms (${auditInactiveFarmSids.join(", ")}). Audits should only contain active farms when distributing credits.`);
|
18935
|
+
}
|
18936
|
+
// Skip Audit: If the audit only contains shortIds that are not active this week, it's irrelevant for this report.
|
18937
|
+
if (auditActiveFarmSids.length === 0) {
|
18938
|
+
continue; // Move to the next audit.
|
18939
|
+
}
|
18940
|
+
// --- Process Valid Audit for Active Farms ---
|
18941
|
+
// Calculate the credit share per active farm within this audit.
|
18942
|
+
const splitValue = new Decimal(adjustedCredit).div(auditActiveFarmSids.length // Divide only by the count of *active* farms found in this audit.
|
18943
|
+
);
|
18944
|
+
// Sanity Check: Ensure the calculated split is not zero.
|
18915
18945
|
if (splitValue.isZero())
|
18916
|
-
throw new Error(`Zero adjustedWeeklyCarbonCredit split in audit ${audit.id}`);
|
18946
|
+
throw new Error(`Zero adjustedWeeklyCarbonCredit split for active farms in audit ${audit.id}`);
|
18947
|
+
// Convert the decimal split value to a bigint using the defined precision.
|
18917
18948
|
const splitBigInt = toBigInt(splitValue, USDG_WEIGHT_DECIMAL_PRECISION);
|
18918
|
-
|
18919
|
-
|
18949
|
+
// Dust Check: Ensure that the conversion to bigint didn't truncate the value to zero.
|
18950
|
+
if (splitBigInt === BigInt(0)) {
|
18951
|
+
throw new Error(`Adjusted credit split for audit ${audit.id} resulted in zero BigInt after conversion for precision ${USDG_WEIGHT_DECIMAL_PRECISION}. Original split value: ${splitValue.toString()}. This might indicate dust loss.`);
|
18952
|
+
}
|
18953
|
+
// Distribute the calculated split value to each active farm associated with this audit.
|
18954
|
+
for (const sidString of auditActiveFarmSids) {
|
18955
|
+
// Duplicate Check: Ensure this shortId hasn't already received credit from another valid audit this week.
|
18956
|
+
if (processedAuditShortIds.has(sidString)) {
|
18957
|
+
throw new Error(`ShortId ${sidString} found in multiple valid audits for week ${week}`);
|
18958
|
+
}
|
18959
|
+
processedAuditShortIds.add(sidString); // Mark this shortId as processed.
|
18960
|
+
// Store the adjusted credit for this active farm.
|
18961
|
+
shortIdToAdjustedCredit.set(sidString, splitBigInt);
|
18962
|
+
}
|
18963
|
+
} // End of loop through audits.
|
18964
|
+
// Final Validation: Ensure every farm considered active for this week received an adjusted credit value from a valid audit.
|
18965
|
+
for (const farmId of farmShortIds) {
|
18966
|
+
if (!shortIdToAdjustedCredit.has(farmId)) {
|
18967
|
+
throw new Error(`Farm ${farmId} is active for week ${week} but has no corresponding adjusted credit found in any valid audit.`);
|
18968
|
+
}
|
18920
18969
|
}
|
18921
|
-
|
18970
|
+
// --- Start Calculation of Merkle Tree Weights ---
|
18971
|
+
let totalCreditsProduced18dp = BigInt(0); // Raw total from farm data, for reporting/comparison.
|
18972
|
+
// Iterate through each active farm to calculate its contribution to the Merkle tree leaves.
|
18922
18973
|
for (const farm of farms) {
|
18974
|
+
// Basic checks for farm data consistency.
|
18923
18975
|
if (farm.status === "Unassigned") {
|
18924
18976
|
throw new Error(`farm ${farm.shortId} is unassigned`);
|
18925
18977
|
}
|
@@ -18929,7 +18981,9 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
18929
18981
|
console.log(`Farm: ${farm.shortId} has ${farm.carbonCreditsProduced} carbon credits produced`);
|
18930
18982
|
throw new Error("Carbon credits produced is less than 0 for farm " + farm.shortId);
|
18931
18983
|
}
|
18984
|
+
// Accumulate the reported carbon credits (18 decimal places).
|
18932
18985
|
totalCreditsProduced18dp += parseUnits(customToFixed(farm.carbonCreditsProduced, 18), 18);
|
18986
|
+
// Validate reward split percentages add up to 1 (within tolerance).
|
18933
18987
|
const sumGlow = farm.rewardSplits.reduce((acc, r) => acc + r.glowSplitPercent, 0);
|
18934
18988
|
const sumUSDG = farm.rewardSplits.reduce((acc, r) => acc + r.usdgSplitPercent, 0);
|
18935
18989
|
const percentTolerance = 1e-12;
|
@@ -18937,57 +18991,76 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
18937
18991
|
throw new Error(`Glow splits ≠1 for farm ${farm.shortId}`);
|
18938
18992
|
if (Math.abs(sumUSDG - 1) > percentTolerance)
|
18939
18993
|
throw new Error(`USDG splits ≠1 for farm ${farm.shortId}`);
|
18994
|
+
// Get the base GLOW payment for the farm, converted to bigint with appropriate precision.
|
18940
18995
|
const glowBase = parseUnits(customToFixed(farm.weeklyPayment, GLOW_WEIGHT_DECIMAL_PRECISION), GLOW_WEIGHT_DECIMAL_PRECISION);
|
18996
|
+
// Retrieve the pre-calculated adjusted credit for this farm. Should always exist due to prior checks.
|
18941
18997
|
const adjustedCreditBigInt = shortIdToAdjustedCredit.get(String(farm.shortId)) ?? BigInt(0);
|
18998
|
+
// Sanity check (likely redundant due to earlier checks, but safe).
|
18942
18999
|
if (adjustedCreditBigInt <= BigInt(0))
|
18943
19000
|
throw new Error(`Adjusted credit is less than or equal to 0 for farm ${farm.shortId}`);
|
19001
|
+
// Process each reward split recipient for this farm.
|
18944
19002
|
for (const split of farm.rewardSplits) {
|
19003
|
+
// Calculate the GLOW weight for this recipient based on the farm's weekly payment and split percentage.
|
18945
19004
|
const glowWeight = multiplyBigIntByDecimalPercentage(glowBase, GLOW_WEIGHT_DECIMAL_PRECISION, split.glowSplitPercent);
|
19005
|
+
// Calculate the USDG weight for this recipient based on the farm's *adjusted* credit and split percentage.
|
18946
19006
|
const usdgWeight = multiplyBigIntByDecimalPercentage(adjustedCreditBigInt, USDG_WEIGHT_DECIMAL_PRECISION, split.usdgSplitPercent);
|
19007
|
+
// Dust Loss Checks: Ensure non-zero percentages didn't result in zero weight due to precision limits.
|
18947
19008
|
if (split.usdgSplitPercent > 0 &&
|
18948
19009
|
adjustedCreditBigInt > BigInt(0) &&
|
18949
19010
|
usdgWeight === BigInt(0))
|
18950
|
-
throw new Error(`USDG dust lost for farm ${farm.shortId}`);
|
19011
|
+
throw new Error(`USDG dust lost for farm ${farm.shortId} wallet ${split.walletAddress}`);
|
18951
19012
|
if (split.glowSplitPercent > 0 &&
|
18952
19013
|
glowBase > BigInt(0) &&
|
18953
19014
|
glowWeight === BigInt(0))
|
18954
|
-
throw new Error(`Glow dust lost for farm ${farm.shortId}`);
|
19015
|
+
throw new Error(`Glow dust lost for farm ${farm.shortId} wallet ${split.walletAddress}`);
|
19016
|
+
// Overflow Check: Ensure individual leaf weights don't exceed the maximum allowed.
|
18955
19017
|
if (glowWeight > MAX_WEIGHT || usdgWeight > MAX_WEIGHT)
|
18956
19018
|
throw new Error(`Leaf weight overflow on wallet ${split.walletAddress}`);
|
19019
|
+
// Accumulate the calculated weights into the map for the recipient wallet.
|
18957
19020
|
accumulateLeafWeights(split.walletAddress, { wallet: split.walletAddress, glowWeight, usdgWeight }, map);
|
18958
19021
|
}
|
18959
19022
|
}
|
19023
|
+
// --- Finalize Merkle Tree and Generate Report Data ---
|
19024
|
+
// Convert the accumulated weights map into the final list of leaves for the tree.
|
18960
19025
|
const finalizedLeaves = Array.from(map.values()).map(({ wallet, glowWeight, usdgWeight }) => ({
|
18961
19026
|
wallet,
|
18962
|
-
glowWeight: glowWeight.toString(),
|
19027
|
+
glowWeight: glowWeight.toString(), // Convert BigInts to strings for hashing/reporting.
|
18963
19028
|
usdgWeight: usdgWeight.toString(),
|
18964
19029
|
}));
|
19030
|
+
// Hash each leaf according to the defined structure.
|
18965
19031
|
const hashedLeaves = finalizedLeaves.map((leaf) => hashLeaf({
|
18966
19032
|
address: leaf.wallet,
|
18967
19033
|
glowWeight: leaf.glowWeight,
|
18968
|
-
usdcWeight: leaf.usdgWeight,
|
19034
|
+
usdcWeight: leaf.usdgWeight, // Note: Parameter name inconsistency (usdc vs usdg)
|
18969
19035
|
}));
|
19036
|
+
// Build the Merkle tree.
|
18970
19037
|
const merkleTree = new MerkleTree(hashedLeaves, ethers.utils.keccak256, {
|
18971
|
-
sort: true,
|
19038
|
+
sort: true, // Ensure consistent tree structure.
|
18972
19039
|
});
|
18973
|
-
const merkleRoot = merkleTree.getHexRoot();
|
19040
|
+
const merkleRoot = merkleTree.getHexRoot(); // Get the root hash.
|
19041
|
+
// Calculate the total weights across all finalized leaves.
|
18974
19042
|
const totalGlowWeight = finalizedLeaves.reduce((acc, { glowWeight }) => acc.add(glowWeight), ethers.BigNumber.from(0));
|
18975
19043
|
const totalUSDGWeight = finalizedLeaves.reduce((acc, { usdgWeight }) => acc.add(usdgWeight), ethers.BigNumber.from(0));
|
19044
|
+
// Total Weight Overflow Checks: Ensure sums don't exceed maximum.
|
18976
19045
|
if (totalGlowWeight.toBigInt() > MAX_WEIGHT)
|
18977
19046
|
throw new Error("Total glow weight overflow");
|
18978
19047
|
if (totalUSDGWeight.toBigInt() > MAX_WEIGHT)
|
18979
19048
|
throw new Error("Total USDG weight overflow");
|
19049
|
+
// Generate Merkle proofs for each leaf and verify them.
|
18980
19050
|
const leavesWithProofs = finalizedLeaves.map((leaf) => {
|
18981
19051
|
const hashed = hashLeaf({
|
18982
19052
|
address: leaf.wallet,
|
18983
19053
|
glowWeight: leaf.glowWeight,
|
18984
|
-
usdcWeight: leaf.usdgWeight,
|
19054
|
+
usdcWeight: leaf.usdgWeight, // Note: Parameter name inconsistency
|
18985
19055
|
});
|
18986
19056
|
const proof = merkleTree.getHexProof(hashed);
|
18987
19057
|
if (!merkleTree.verify(proof, hashed, merkleRoot))
|
19058
|
+
// Verify proof against the calculated root.
|
18988
19059
|
throw new Error("Invalid proof for " + leaf.wallet);
|
18989
19060
|
return { ...leaf, proof };
|
18990
19061
|
});
|
19062
|
+
// --- Sanity Checks on Final Weights ---
|
19063
|
+
// Verify that summing weights from leavesWithProofs matches the earlier reduce calculation.
|
18991
19064
|
const glowSumProofLoop = leavesWithProofs.reduce((acc, l) => acc.add(l.glowWeight), ethers.BigNumber.from(0));
|
18992
19065
|
if (!glowSumProofLoop.eq(totalGlowWeight)) {
|
18993
19066
|
console.error("Glow Weight Sum Mismatch (Post-73):");
|
@@ -19002,43 +19075,55 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19002
19075
|
console.error("Sum from reduce:", totalUSDGWeight.toString());
|
19003
19076
|
throw new Error("USDG sum mismatch");
|
19004
19077
|
}
|
19078
|
+
// Calculate the total expected credits based on the adjusted values used.
|
19005
19079
|
const totalExpectedCredits = farms.reduce((acc, f) => {
|
19006
19080
|
const adj = shortIdToAdjustedCredit.get(String(f.shortId)) ?? BigInt(0);
|
19007
19081
|
return acc.plus(fromBigInt(adj, USDG_WEIGHT_DECIMAL_PRECISION));
|
19008
19082
|
}, new Decimal(0));
|
19083
|
+
// Convert total USDG weight back to human-readable decimal for deviation check.
|
19009
19084
|
const totalUSDGWeightHuman = new Decimal(formatUnits(BigInt(totalUSDGWeight.toString()), USDG_WEIGHT_DECIMAL_PRECISION));
|
19010
|
-
|
19085
|
+
// Check deviation between total adjusted credits used and the final sum of USDG weights.
|
19086
|
+
if (greaterThanMaxDeviation(totalExpectedCredits.toNumber(), totalUSDGWeightHuman.toNumber(), 0.001 // 0.1% tolerance
|
19087
|
+
)) {
|
19011
19088
|
console.error("Deviation Check Failed (Post-73): Expected Credits vs USDG Weight");
|
19012
19089
|
console.error("Total Expected Credits:", totalExpectedCredits.toNumber());
|
19013
19090
|
console.error("Total USDG Weight:", totalUSDGWeightHuman.toNumber());
|
19014
19091
|
console.error("Allowed Deviation:", 0.001);
|
19015
19092
|
throw new Error("totalExpectedCredits vs USDG weight deviation >0.1% ");
|
19016
19093
|
}
|
19094
|
+
// Convert total Glow weight back to human-readable decimal.
|
19017
19095
|
const totalGlowWeightHuman = new Decimal(formatUnits(BigInt(totalGlowWeight.toString()), GLOW_WEIGHT_DECIMAL_PRECISION));
|
19096
|
+
// Sum the original weekly protocol fee payments from farm data.
|
19018
19097
|
const totalProtocolFeePayments = farms.reduce((acc, f) => acc + f.weeklyPayment, 0);
|
19019
|
-
|
19098
|
+
// Check deviation between total glow weight and total protocol fees paid.
|
19099
|
+
if (greaterThanMaxDeviation(totalGlowWeightHuman.toNumber(), totalProtocolFeePayments, 0.001 // 0.1% tolerance
|
19100
|
+
)) {
|
19020
19101
|
console.error("Deviation Check Failed (Post-73): Glow Weight vs Protocol Fees");
|
19021
19102
|
console.error("Total Glow Weight:", totalGlowWeightHuman.toNumber());
|
19022
19103
|
console.error("Total Protocol Fees:", totalProtocolFeePayments);
|
19023
19104
|
console.error("Allowed Deviation:", 0.001);
|
19024
19105
|
throw new Error("totalGlowWeight vs protocol fees deviation >0.1% ");
|
19025
19106
|
}
|
19107
|
+
// --- Prepare Output Data ---
|
19108
|
+
// Key statistics for the report.
|
19026
19109
|
const headlineStats = {
|
19027
19110
|
weekNumber: week,
|
19028
|
-
totalCreditsProduced: formatUnits(totalCreditsProduced18dp, 18),
|
19111
|
+
totalCreditsProduced: formatUnits(totalCreditsProduced18dp, 18), // Original reported total
|
19029
19112
|
totalCreditsProducedBN: totalCreditsProduced18dp.toString(),
|
19030
|
-
totalGlowWeightInFinalized: totalGlowWeight.toString(),
|
19031
|
-
totalGlowWeightHuman: totalGlowWeightHuman.toString(),
|
19113
|
+
totalGlowWeightInFinalized: totalGlowWeight.toString(), // Total weight as BigNumber string
|
19114
|
+
totalGlowWeightHuman: totalGlowWeightHuman.toString(), // Total weight as human-readable decimal
|
19032
19115
|
totalUSDGWeightInFinalized: totalUSDGWeight.toString(),
|
19033
19116
|
totalUSDGWeightHuman: totalUSDGWeightHuman.toString(),
|
19034
19117
|
root: merkleRoot,
|
19035
19118
|
glowWeightDecimals: GLOW_WEIGHT_DECIMAL_PRECISION,
|
19036
19119
|
usdgWeightDecimals: USDG_WEIGHT_DECIMAL_PRECISION,
|
19037
19120
|
};
|
19121
|
+
// List of shortIds and their final adjusted credit value (human-readable).
|
19038
19122
|
const shortIdAdjustedList = Array.from(shortIdToAdjustedCredit.entries()).map(([shortId, creditBigInt]) => ({
|
19039
19123
|
shortId,
|
19040
19124
|
adjustedCredit: fromBigInt(creditBigInt, USDG_WEIGHT_DECIMAL_PRECISION).toString(),
|
19041
19125
|
}));
|
19126
|
+
// Detailed comparison between originally reported credits and adjusted credits for each farm.
|
19042
19127
|
const creditsDeviationList = farms.map((farm) => {
|
19043
19128
|
const adj = shortIdToAdjustedCredit.get(String(farm.shortId)) ?? BigInt(0);
|
19044
19129
|
const adjusted = fromBigInt(adj, USDG_WEIGHT_DECIMAL_PRECISION);
|
@@ -19046,6 +19131,7 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19046
19131
|
let deviation;
|
19047
19132
|
let absDeviation;
|
19048
19133
|
let deviationPercent;
|
19134
|
+
// Handle division by zero if produced is zero.
|
19049
19135
|
if (produced.isZero() && adjusted.isZero()) {
|
19050
19136
|
deviation = new Decimal(0);
|
19051
19137
|
absDeviation = new Decimal(0);
|
@@ -19055,7 +19141,7 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19055
19141
|
deviation = produced.minus(adjusted);
|
19056
19142
|
absDeviation = deviation.abs();
|
19057
19143
|
deviationPercent = deviation
|
19058
|
-
.div(produced.isZero() ? 1 : produced)
|
19144
|
+
.div(produced.isZero() ? 1 : produced) // Avoid division by zero
|
19059
19145
|
.mul(100);
|
19060
19146
|
}
|
19061
19147
|
return {
|
@@ -19067,16 +19153,569 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19067
19153
|
deviationPercent: deviationPercent.toNumber(),
|
19068
19154
|
};
|
19069
19155
|
});
|
19156
|
+
// Return all calculated data.
|
19070
19157
|
return {
|
19071
19158
|
headlineStats,
|
19072
|
-
finalizedLeaves,
|
19073
|
-
leavesWithProofs,
|
19074
|
-
farms,
|
19075
|
-
rawData,
|
19076
|
-
shortIdAdjustedList,
|
19077
|
-
creditsDeviationList,
|
19159
|
+
finalizedLeaves, // Leaves without proofs (for potential use cases)
|
19160
|
+
leavesWithProofs, // Leaves with proofs (primary data for distribution)
|
19161
|
+
farms, // Original filtered farm data
|
19162
|
+
rawData, // Raw GCA responses
|
19163
|
+
shortIdAdjustedList, // List of adjusted credits per farm
|
19164
|
+
creditsDeviationList, // Detailed deviation report per farm
|
19165
|
+
};
|
19166
|
+
}
|
19167
|
+
|
19168
|
+
const FORWARDER_ABI = [
|
19169
|
+
{
|
19170
|
+
inputs: [{ internalType: "address", name: "_forwarder", type: "address" }],
|
19171
|
+
stateMutability: "nonpayable",
|
19172
|
+
type: "constructor",
|
19173
|
+
},
|
19174
|
+
{
|
19175
|
+
inputs: [{ internalType: "address", name: "target", type: "address" }],
|
19176
|
+
name: "AddressEmptyCode",
|
19177
|
+
type: "error",
|
19178
|
+
},
|
19179
|
+
{
|
19180
|
+
inputs: [{ internalType: "address", name: "account", type: "address" }],
|
19181
|
+
name: "AddressInsufficientBalance",
|
19182
|
+
type: "error",
|
19183
|
+
},
|
19184
|
+
{ inputs: [], name: "FailedInnerCall", type: "error" },
|
19185
|
+
{
|
19186
|
+
inputs: [{ internalType: "address", name: "token", type: "address" }],
|
19187
|
+
name: "SafeERC20FailedOperation",
|
19188
|
+
type: "error",
|
19189
|
+
},
|
19190
|
+
{
|
19191
|
+
anonymous: false,
|
19192
|
+
inputs: [
|
19193
|
+
{ indexed: true, internalType: "address", name: "from", type: "address" },
|
19194
|
+
{ indexed: true, internalType: "address", name: "to", type: "address" },
|
19195
|
+
{
|
19196
|
+
indexed: true,
|
19197
|
+
internalType: "address",
|
19198
|
+
name: "token",
|
19199
|
+
type: "address",
|
19200
|
+
},
|
19201
|
+
{
|
19202
|
+
indexed: false,
|
19203
|
+
internalType: "uint256",
|
19204
|
+
name: "amount",
|
19205
|
+
type: "uint256",
|
19206
|
+
},
|
19207
|
+
{
|
19208
|
+
indexed: false,
|
19209
|
+
internalType: "string",
|
19210
|
+
name: "message",
|
19211
|
+
type: "string",
|
19212
|
+
},
|
19213
|
+
],
|
19214
|
+
name: "Forward",
|
19215
|
+
type: "event",
|
19216
|
+
},
|
19217
|
+
{
|
19218
|
+
inputs: [],
|
19219
|
+
name: "FORWARD_ADDRESS",
|
19220
|
+
outputs: [{ internalType: "address", name: "", type: "address" }],
|
19221
|
+
stateMutability: "view",
|
19222
|
+
type: "function",
|
19223
|
+
},
|
19224
|
+
{
|
19225
|
+
inputs: [
|
19226
|
+
{ internalType: "address", name: "token", type: "address" },
|
19227
|
+
{ internalType: "address", name: "to", type: "address" },
|
19228
|
+
{ internalType: "uint256", name: "amount", type: "uint256" },
|
19229
|
+
{ internalType: "string", name: "message", type: "string" },
|
19230
|
+
],
|
19231
|
+
name: "forward",
|
19232
|
+
outputs: [],
|
19233
|
+
stateMutability: "nonpayable",
|
19234
|
+
type: "function",
|
19235
|
+
},
|
19236
|
+
];
|
19237
|
+
|
19238
|
+
const ERC20_ABI = [
|
19239
|
+
{
|
19240
|
+
inputs: [
|
19241
|
+
{ name: "spender", type: "address" },
|
19242
|
+
{ name: "amount", type: "uint256" },
|
19243
|
+
],
|
19244
|
+
name: "approve",
|
19245
|
+
outputs: [{ name: "", type: "bool" }],
|
19246
|
+
stateMutability: "nonpayable",
|
19247
|
+
type: "function",
|
19248
|
+
},
|
19249
|
+
{
|
19250
|
+
inputs: [
|
19251
|
+
{ name: "owner", type: "address" },
|
19252
|
+
{ name: "spender", type: "address" },
|
19253
|
+
],
|
19254
|
+
name: "allowance",
|
19255
|
+
outputs: [{ name: "", type: "uint256" }],
|
19256
|
+
stateMutability: "view",
|
19257
|
+
type: "function",
|
19258
|
+
},
|
19259
|
+
{
|
19260
|
+
inputs: [
|
19261
|
+
{ name: "to", type: "address" },
|
19262
|
+
{ name: "amount", type: "uint256" },
|
19263
|
+
],
|
19264
|
+
name: "transfer",
|
19265
|
+
outputs: [{ name: "", type: "bool" }],
|
19266
|
+
stateMutability: "nonpayable",
|
19267
|
+
type: "function",
|
19268
|
+
},
|
19269
|
+
{
|
19270
|
+
inputs: [{ name: "account", type: "address" }],
|
19271
|
+
name: "balanceOf",
|
19272
|
+
outputs: [{ name: "", type: "uint256" }],
|
19273
|
+
stateMutability: "view",
|
19274
|
+
type: "function",
|
19275
|
+
},
|
19276
|
+
{
|
19277
|
+
inputs: [
|
19278
|
+
{ name: "account", type: "address" },
|
19279
|
+
{ name: "amount", type: "uint256" },
|
19280
|
+
],
|
19281
|
+
name: "mint",
|
19282
|
+
outputs: [{ name: "", type: "bool" }],
|
19283
|
+
stateMutability: "nonpayable",
|
19284
|
+
type: "function",
|
19285
|
+
},
|
19286
|
+
];
|
19287
|
+
|
19288
|
+
// Contract-specific addresses
|
19289
|
+
const mainnetAddresses = {
|
19290
|
+
USDG: "0xe010ec500720bE9EF3F82129E7eD2Ee1FB7955F2",
|
19291
|
+
GLW: "0xf4fbC617A5733EAAF9af08E1Ab816B103388d8B6",
|
19292
|
+
USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
19293
|
+
FORWARDER: "0x0000000000000000000000000000000000000000", // TODO: Update with actual mainnet address
|
19294
|
+
FOUNDATION_WALLET: "0x0000000000000000000000000000000000000000", // TODO: Update with actual mainnet foundation wallet
|
19295
|
+
};
|
19296
|
+
const sepoliaAddresses = {
|
19297
|
+
USDG: "0xda78313A3fF949890112c1B746AB1c75d1b1c17B",
|
19298
|
+
GLW: "0x2039161fcE4C8e5CF5FE64e17Fd290E8dFF3c9BD",
|
19299
|
+
USDC: "0x93c898be98cd2618ba84a6dccf5003d3bbe40356",
|
19300
|
+
FORWARDER: "0x9c1d61303D46BFAb1eC5F25c12A1Bf4cB3d06416",
|
19301
|
+
FOUNDATION_WALLET: "0x5e230FED487c86B90f6508104149F087d9B1B0A7",
|
19302
|
+
};
|
19303
|
+
const getAddresses = (CHAIN_ID) => {
|
19304
|
+
switch (CHAIN_ID) {
|
19305
|
+
case 1:
|
19306
|
+
return mainnetAddresses;
|
19307
|
+
case 11155111:
|
19308
|
+
return sepoliaAddresses;
|
19309
|
+
default:
|
19310
|
+
console.warn(`Unsupported chain ID: ${CHAIN_ID}, falling back to mainnet addresses`);
|
19311
|
+
return mainnetAddresses;
|
19312
|
+
}
|
19313
|
+
};
|
19314
|
+
|
19315
|
+
var ForwarderError;
|
19316
|
+
(function (ForwarderError) {
|
19317
|
+
ForwarderError["CONTRACT_NOT_AVAILABLE"] = "Contract not available";
|
19318
|
+
ForwarderError["SIGNER_NOT_AVAILABLE"] = "Signer not available";
|
19319
|
+
ForwarderError["UNKNOWN_ERROR"] = "Unknown error";
|
19320
|
+
ForwarderError["INVALID_FORWARD_TYPE"] = "Invalid forward type";
|
19321
|
+
ForwarderError["MISSING_REQUIRED_PARAMS"] = "Missing required parameters";
|
19322
|
+
})(ForwarderError || (ForwarderError = {}));
|
19323
|
+
// Utility to extract the most useful revert reason from an ethers error object
|
19324
|
+
function parseEthersError(error) {
|
19325
|
+
if (!error)
|
19326
|
+
return "Unknown error";
|
19327
|
+
const possibleError = error;
|
19328
|
+
// If the error originates from a callStatic it will often be found at `error?.error?.body`
|
19329
|
+
if (possibleError?.error?.body) {
|
19330
|
+
try {
|
19331
|
+
const body = JSON.parse(possibleError.error.body);
|
19332
|
+
// Hardhat style errors
|
19333
|
+
if (body?.error?.message)
|
19334
|
+
return body.error.message;
|
19335
|
+
}
|
19336
|
+
catch { }
|
19337
|
+
}
|
19338
|
+
// Found on MetaMask/Alchemy shape errors
|
19339
|
+
if (possibleError?.data?.message)
|
19340
|
+
return possibleError.data.message;
|
19341
|
+
if (possibleError?.error?.message)
|
19342
|
+
return possibleError.error.message;
|
19343
|
+
// Standard ethers v5 message
|
19344
|
+
if (possibleError?.reason)
|
19345
|
+
return possibleError.reason;
|
19346
|
+
if (possibleError?.message)
|
19347
|
+
return possibleError.message;
|
19348
|
+
return ForwarderError.UNKNOWN_ERROR;
|
19349
|
+
}
|
19350
|
+
// Type-guard style helper to ensure a signer exists throughout the rest of the function.
|
19351
|
+
function assertSigner(maybeSigner) {
|
19352
|
+
if (!maybeSigner) {
|
19353
|
+
throw new Error(ForwarderError.SIGNER_NOT_AVAILABLE);
|
19354
|
+
}
|
19355
|
+
}
|
19356
|
+
function useForwarder(signer, CHAIN_ID) {
|
19357
|
+
// Use dynamic addresses based on chain configuration
|
19358
|
+
const ADDRESSES = getAddresses(CHAIN_ID);
|
19359
|
+
// Framework-agnostic processing flag
|
19360
|
+
let isProcessing = false;
|
19361
|
+
const setIsProcessing = (value) => {
|
19362
|
+
isProcessing = value;
|
19363
|
+
};
|
19364
|
+
// Returns a contract instance for Forwarder
|
19365
|
+
function getForwarderContract() {
|
19366
|
+
assertSigner(signer);
|
19367
|
+
return new ethers.Contract(ADDRESSES.FORWARDER, FORWARDER_ABI, signer);
|
19368
|
+
}
|
19369
|
+
/**
|
19370
|
+
* Construct the message for the forward call based on type and parameters
|
19371
|
+
*/
|
19372
|
+
function constructForwardMessage(params) {
|
19373
|
+
const { type, applicationId, farmId, regionId, userAddress } = params;
|
19374
|
+
switch (type) {
|
19375
|
+
case "PayProtocolFeeAndMintGCTLAndStake":
|
19376
|
+
if (!applicationId) {
|
19377
|
+
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19378
|
+
}
|
19379
|
+
return `PayProtocolFeeAndMintGCTLAndStake::${applicationId}`;
|
19380
|
+
case "PayProtocolFee":
|
19381
|
+
if (!applicationId) {
|
19382
|
+
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19383
|
+
}
|
19384
|
+
return `PayProtocolFee::${applicationId}`;
|
19385
|
+
case "MintGCTLAndStake":
|
19386
|
+
if (!regionId) {
|
19387
|
+
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19388
|
+
}
|
19389
|
+
return `MintGCTLAndStake::${regionId}`;
|
19390
|
+
case "MintGCTL":
|
19391
|
+
if (!userAddress) {
|
19392
|
+
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19393
|
+
}
|
19394
|
+
return `MintGCTL::${userAddress}`;
|
19395
|
+
case "BuySolarFarm":
|
19396
|
+
if (!farmId) {
|
19397
|
+
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19398
|
+
}
|
19399
|
+
return `BuySolarFarm::${farmId}`;
|
19400
|
+
default:
|
19401
|
+
throw new Error(ForwarderError.INVALID_FORWARD_TYPE);
|
19402
|
+
}
|
19403
|
+
}
|
19404
|
+
/**
|
19405
|
+
* Get the appropriate token contract based on currency
|
19406
|
+
*/
|
19407
|
+
function getTokenContract(currency = "USDC") {
|
19408
|
+
assertSigner(signer);
|
19409
|
+
let tokenAddress;
|
19410
|
+
switch (currency) {
|
19411
|
+
case "USDC":
|
19412
|
+
tokenAddress = ADDRESSES.USDC;
|
19413
|
+
break;
|
19414
|
+
case "GLW":
|
19415
|
+
tokenAddress = ADDRESSES.GLW;
|
19416
|
+
break;
|
19417
|
+
case "USDG":
|
19418
|
+
tokenAddress = ADDRESSES.USDG;
|
19419
|
+
break;
|
19420
|
+
default:
|
19421
|
+
throw new Error(`Currency ${currency} not yet supported. Only USDC, GLW, and USDG are currently supported.`);
|
19422
|
+
}
|
19423
|
+
return new ethers.Contract(tokenAddress, ERC20_ABI, signer);
|
19424
|
+
}
|
19425
|
+
/**
|
19426
|
+
* Check current token allowance for the forwarder contract
|
19427
|
+
* @param owner The wallet address to check allowance for
|
19428
|
+
* @param currency The currency to check allowance for
|
19429
|
+
*/
|
19430
|
+
async function checkTokenAllowance(owner, currency = "USDC") {
|
19431
|
+
assertSigner(signer);
|
19432
|
+
try {
|
19433
|
+
const tokenContract = getTokenContract(currency);
|
19434
|
+
if (!tokenContract)
|
19435
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19436
|
+
const allowance = await tokenContract.allowance(owner, ADDRESSES.FORWARDER);
|
19437
|
+
return allowance;
|
19438
|
+
}
|
19439
|
+
catch (error) {
|
19440
|
+
throw new Error(parseEthersError(error));
|
19441
|
+
}
|
19442
|
+
}
|
19443
|
+
/**
|
19444
|
+
* Check user's token balance
|
19445
|
+
* @param owner The wallet address to check balance for
|
19446
|
+
* @param currency The currency to check balance for
|
19447
|
+
*/
|
19448
|
+
async function checkTokenBalance(owner, currency = "USDC") {
|
19449
|
+
assertSigner(signer);
|
19450
|
+
try {
|
19451
|
+
const tokenContract = getTokenContract(currency);
|
19452
|
+
if (!tokenContract)
|
19453
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19454
|
+
const balance = await tokenContract.balanceOf(owner);
|
19455
|
+
return balance;
|
19456
|
+
}
|
19457
|
+
catch (error) {
|
19458
|
+
throw new Error(parseEthersError(error));
|
19459
|
+
}
|
19460
|
+
}
|
19461
|
+
/**
|
19462
|
+
* Approve tokens for the forwarder contract
|
19463
|
+
* @param amount Amount to approve (BigNumber)
|
19464
|
+
* @param currency The currency to approve
|
19465
|
+
*/
|
19466
|
+
async function approveToken(amount, currency = "USDC") {
|
19467
|
+
assertSigner(signer);
|
19468
|
+
try {
|
19469
|
+
const tokenContract = getTokenContract(currency);
|
19470
|
+
if (!tokenContract)
|
19471
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19472
|
+
setIsProcessing(true);
|
19473
|
+
// Approve only the specific amount needed
|
19474
|
+
const approveTx = await tokenContract.approve(ADDRESSES.FORWARDER, amount);
|
19475
|
+
await approveTx.wait();
|
19476
|
+
return true;
|
19477
|
+
}
|
19478
|
+
catch (error) {
|
19479
|
+
throw new Error(parseEthersError(error));
|
19480
|
+
}
|
19481
|
+
finally {
|
19482
|
+
setIsProcessing(false);
|
19483
|
+
}
|
19484
|
+
}
|
19485
|
+
/**
|
19486
|
+
* Forward tokens through the forwarder contract with type-specific handling
|
19487
|
+
* @param params Forward parameters including type, amount, and required fields
|
19488
|
+
*/
|
19489
|
+
async function forwardTokens(params) {
|
19490
|
+
assertSigner(signer);
|
19491
|
+
try {
|
19492
|
+
const forwarderContract = getForwarderContract();
|
19493
|
+
if (!forwarderContract)
|
19494
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19495
|
+
setIsProcessing(true);
|
19496
|
+
const { amount, currency = "USDC" } = params;
|
19497
|
+
const tokenContract = getTokenContract(currency);
|
19498
|
+
if (!tokenContract)
|
19499
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19500
|
+
const owner = await signer.getAddress();
|
19501
|
+
// Construct the appropriate message for this forward type
|
19502
|
+
const message = constructForwardMessage(params);
|
19503
|
+
// Check allowance and approve if necessary
|
19504
|
+
const allowance = await tokenContract.allowance(owner, ADDRESSES.FORWARDER);
|
19505
|
+
if (allowance.lt(amount)) {
|
19506
|
+
try {
|
19507
|
+
const approveTx = await tokenContract.approve(ADDRESSES.FORWARDER, ethers.constants.MaxUint256);
|
19508
|
+
await approveTx.wait();
|
19509
|
+
}
|
19510
|
+
catch (approveError) {
|
19511
|
+
throw new Error(parseEthersError(approveError) || "Token approval failed");
|
19512
|
+
}
|
19513
|
+
}
|
19514
|
+
// Get the token address based on currency
|
19515
|
+
let tokenAddress;
|
19516
|
+
switch (currency) {
|
19517
|
+
case "USDC":
|
19518
|
+
tokenAddress = ADDRESSES.USDC;
|
19519
|
+
break;
|
19520
|
+
case "USDG":
|
19521
|
+
tokenAddress = ADDRESSES.USDG;
|
19522
|
+
break;
|
19523
|
+
case "GLW":
|
19524
|
+
tokenAddress = ADDRESSES.GLW;
|
19525
|
+
break;
|
19526
|
+
default:
|
19527
|
+
throw new Error(`Unsupported currency for forwarding: ${currency}`);
|
19528
|
+
}
|
19529
|
+
// Run a static call first to surface any revert reason
|
19530
|
+
try {
|
19531
|
+
await forwarderContract.callStatic.forward(tokenAddress, ADDRESSES.FOUNDATION_WALLET, amount, message, { from: owner });
|
19532
|
+
}
|
19533
|
+
catch (staticError) {
|
19534
|
+
throw new Error(parseEthersError(staticError));
|
19535
|
+
}
|
19536
|
+
// Execute the forward transaction
|
19537
|
+
const tx = await forwarderContract.forward(tokenAddress, ADDRESSES.FOUNDATION_WALLET, amount, message);
|
19538
|
+
await tx.wait();
|
19539
|
+
return tx.hash;
|
19540
|
+
}
|
19541
|
+
catch (txError) {
|
19542
|
+
throw new Error(parseEthersError(txError));
|
19543
|
+
}
|
19544
|
+
finally {
|
19545
|
+
setIsProcessing(false);
|
19546
|
+
}
|
19547
|
+
}
|
19548
|
+
/**
|
19549
|
+
* Forward tokens for protocol fee payment and GCTL minting with staking
|
19550
|
+
*/
|
19551
|
+
async function payProtocolFeeAndMintGCTLAndStake(amount, userAddress, applicationId, regionId, currency = "USDC") {
|
19552
|
+
assertSigner(signer);
|
19553
|
+
// GCTL minting only supports USDC and USDG
|
19554
|
+
if (currency === "GLW") {
|
19555
|
+
throw new Error("GCTL minting is not supported with GLW payment. Use USDC or USDG.");
|
19556
|
+
}
|
19557
|
+
return forwardTokens({
|
19558
|
+
amount,
|
19559
|
+
userAddress,
|
19560
|
+
type: "PayProtocolFeeAndMintGCTLAndStake",
|
19561
|
+
currency,
|
19562
|
+
applicationId,
|
19563
|
+
regionId,
|
19564
|
+
});
|
19565
|
+
}
|
19566
|
+
/**
|
19567
|
+
* Forward tokens for protocol fee payment only
|
19568
|
+
*/
|
19569
|
+
async function payProtocolFee(amount, userAddress, applicationId, currency = "USDC") {
|
19570
|
+
assertSigner(signer);
|
19571
|
+
return forwardTokens({
|
19572
|
+
amount,
|
19573
|
+
userAddress,
|
19574
|
+
type: "PayProtocolFee",
|
19575
|
+
currency,
|
19576
|
+
applicationId,
|
19577
|
+
});
|
19578
|
+
}
|
19579
|
+
/**
|
19580
|
+
* Forward USDC to mint GCTL and stake to a region
|
19581
|
+
*/
|
19582
|
+
async function mintGCTLAndStake(amount, userAddress, regionId) {
|
19583
|
+
assertSigner(signer);
|
19584
|
+
return forwardTokens({
|
19585
|
+
amount,
|
19586
|
+
userAddress,
|
19587
|
+
type: "MintGCTLAndStake",
|
19588
|
+
currency: "USDC",
|
19589
|
+
regionId,
|
19590
|
+
});
|
19591
|
+
}
|
19592
|
+
/**
|
19593
|
+
* Forward USDC to mint GCTL (existing functionality, keeping for compatibility)
|
19594
|
+
*/
|
19595
|
+
async function mintGCTL(amount, userAddress) {
|
19596
|
+
assertSigner(signer);
|
19597
|
+
return forwardTokens({
|
19598
|
+
amount,
|
19599
|
+
userAddress,
|
19600
|
+
type: "MintGCTL",
|
19601
|
+
currency: "USDC",
|
19602
|
+
});
|
19603
|
+
}
|
19604
|
+
/**
|
19605
|
+
* Forward tokens to buy a solar farm
|
19606
|
+
*/
|
19607
|
+
async function buySolarFarm(amount, userAddress, farmId, currency = "USDC") {
|
19608
|
+
assertSigner(signer);
|
19609
|
+
return forwardTokens({
|
19610
|
+
amount,
|
19611
|
+
userAddress,
|
19612
|
+
type: "BuySolarFarm",
|
19613
|
+
currency,
|
19614
|
+
farmId,
|
19615
|
+
});
|
19616
|
+
}
|
19617
|
+
/**
|
19618
|
+
* Estimate gas for forwarding with type-specific handling
|
19619
|
+
* @param params Forward parameters
|
19620
|
+
* @param ethPriceInUSD Current ETH price in USD (for cost estimation)
|
19621
|
+
*/
|
19622
|
+
async function estimateGasForForward(params, ethPriceInUSD) {
|
19623
|
+
assertSigner(signer);
|
19624
|
+
try {
|
19625
|
+
const forwarderContract = getForwarderContract();
|
19626
|
+
if (!forwarderContract)
|
19627
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19628
|
+
const { amount, currency = "USDC" } = params;
|
19629
|
+
// Construct the appropriate message for this forward type
|
19630
|
+
const message = constructForwardMessage(params);
|
19631
|
+
// Get token address
|
19632
|
+
let tokenAddress;
|
19633
|
+
switch (currency) {
|
19634
|
+
case "USDC":
|
19635
|
+
tokenAddress = ADDRESSES.USDC;
|
19636
|
+
break;
|
19637
|
+
case "USDG":
|
19638
|
+
tokenAddress = ADDRESSES.USDG;
|
19639
|
+
break;
|
19640
|
+
case "GLW":
|
19641
|
+
tokenAddress = ADDRESSES.GLW;
|
19642
|
+
break;
|
19643
|
+
default:
|
19644
|
+
throw new Error(`Unsupported currency for gas estimation: ${currency}`);
|
19645
|
+
}
|
19646
|
+
const gasPrice = await signer.getGasPrice();
|
19647
|
+
const estimatedGas = await forwarderContract.estimateGas.forward(tokenAddress, ADDRESSES.FOUNDATION_WALLET, amount, message);
|
19648
|
+
const estimatedCost = estimatedGas.mul(gasPrice);
|
19649
|
+
if (ethPriceInUSD) {
|
19650
|
+
const estimatedCostInEth = ethers.utils.formatEther(estimatedCost);
|
19651
|
+
const estimatedCostInUSD = (parseFloat(estimatedCostInEth) * ethPriceInUSD).toFixed(2);
|
19652
|
+
return estimatedCostInUSD;
|
19653
|
+
}
|
19654
|
+
else {
|
19655
|
+
throw new Error("Could not fetch the ETH price to calculate cost in USD.");
|
19656
|
+
}
|
19657
|
+
}
|
19658
|
+
catch (error) {
|
19659
|
+
throw new Error(parseEthersError(error));
|
19660
|
+
}
|
19661
|
+
}
|
19662
|
+
/**
|
19663
|
+
* Mint test USDC (only works on testnets with mintable USDC contracts)
|
19664
|
+
* @param amount Amount of USDC to mint (BigNumber, 6 decimals)
|
19665
|
+
* @param recipient Address to mint USDC to
|
19666
|
+
*/
|
19667
|
+
async function mintTestUSDC(amount, recipient) {
|
19668
|
+
assertSigner(signer);
|
19669
|
+
if (CHAIN_ID !== 11155111) {
|
19670
|
+
throw new Error("Minting test USDC is only supported on Sepolia");
|
19671
|
+
}
|
19672
|
+
try {
|
19673
|
+
const usdcContract = getTokenContract("USDC"); // Use getTokenContract for consistency
|
19674
|
+
if (!usdcContract)
|
19675
|
+
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19676
|
+
setIsProcessing(true);
|
19677
|
+
// Try to call mint function (common for test tokens)
|
19678
|
+
const tx = await usdcContract.mint(recipient, amount);
|
19679
|
+
await tx.wait();
|
19680
|
+
return tx.hash;
|
19681
|
+
}
|
19682
|
+
catch (error) {
|
19683
|
+
// If mint function doesn't exist or fails, provide helpful error
|
19684
|
+
const errorMessage = parseEthersError(error);
|
19685
|
+
if (errorMessage.includes("mint")) {
|
19686
|
+
throw new Error("This USDC contract doesn't support minting");
|
19687
|
+
}
|
19688
|
+
throw new Error(errorMessage);
|
19689
|
+
}
|
19690
|
+
finally {
|
19691
|
+
setIsProcessing(false);
|
19692
|
+
}
|
19693
|
+
}
|
19694
|
+
return {
|
19695
|
+
// New methods for different forward types
|
19696
|
+
forwardTokens,
|
19697
|
+
payProtocolFeeAndMintGCTLAndStake,
|
19698
|
+
payProtocolFee,
|
19699
|
+
mintGCTLAndStake,
|
19700
|
+
mintGCTL,
|
19701
|
+
buySolarFarm,
|
19702
|
+
// Token operations
|
19703
|
+
approveToken,
|
19704
|
+
checkTokenAllowance,
|
19705
|
+
checkTokenBalance,
|
19706
|
+
// Utility methods
|
19707
|
+
estimateGasForForward,
|
19708
|
+
mintTestUSDC,
|
19709
|
+
constructForwardMessage,
|
19710
|
+
// State
|
19711
|
+
get isProcessing() {
|
19712
|
+
return isProcessing;
|
19713
|
+
},
|
19714
|
+
addresses: ADDRESSES,
|
19715
|
+
// Signer availability
|
19716
|
+
isSignerAvailable: !!signer,
|
19078
19717
|
};
|
19079
19718
|
}
|
19080
19719
|
|
19081
|
-
export { GENESIS_TIMESTAMP, createWeeklyReport, createWeeklyReportLegacy };
|
19720
|
+
export { GENESIS_TIMESTAMP, createWeeklyReport, createWeeklyReportLegacy, useForwarder };
|
19082
19721
|
//# sourceMappingURL=index.js.map
|