@glowlabs-org/utils 0.2.1 → 0.2.3
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/dist/cjs/browser.js +20 -0
- package/dist/cjs/browser.js.map +1 -0
- package/dist/cjs/index.js +31 -597
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/use-forwarder-CVlJS4UY.js +586 -0
- package/dist/cjs/use-forwarder-CVlJS4UY.js.map +1 -0
- package/dist/esm/browser.js +3 -0
- package/dist/esm/browser.js.map +1 -0
- package/dist/esm/index.js +3 -568
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/use-forwarder-DD_5ZFZg.js +577 -0
- package/dist/esm/use-forwarder-DD_5ZFZg.js.map +1 -0
- package/package.json +22 -1
- package/rollup.config.js +10 -3
package/dist/cjs/index.js
CHANGED
@@ -15,6 +15,7 @@ var viem = require('viem');
|
|
15
15
|
var merkletreejs = require('merkletreejs');
|
16
16
|
var ethers = require('ethers');
|
17
17
|
var Decimal = require('decimal.js');
|
18
|
+
var useForwarder = require('./use-forwarder-CVlJS4UY.js');
|
18
19
|
|
19
20
|
const GENESIS_TIMESTAMP = 1700352000;
|
20
21
|
|
@@ -18628,8 +18629,6 @@ function customToFixed(num, precision) {
|
|
18628
18629
|
return fixed;
|
18629
18630
|
}
|
18630
18631
|
|
18631
|
-
const HUB_URL = "https://glow.org";
|
18632
|
-
|
18633
18632
|
function multiplyBigIntByDecimalPercentage(bigInt, numberOfDecimals, percentage) {
|
18634
18633
|
const DENOMINATOR = BigInt(10 ** numberOfDecimals);
|
18635
18634
|
const percentageAsBigNum = BigInt(viem.parseUnits(customToFixed(percentage, numberOfDecimals), numberOfDecimals));
|
@@ -18693,19 +18692,6 @@ function accumulateLeafWeights(key, value, map) {
|
|
18693
18692
|
// Numeric string regex: matches valid numbers (digits, optional single dot, digits after dot)
|
18694
18693
|
const NUMERIC_REGEX = /^(?:\d+\.?\d*|\.\d+)$/;
|
18695
18694
|
|
18696
|
-
/**
|
18697
|
-
* @dev This is actually not as intuitive as it seems.
|
18698
|
-
* Glow actually has 18 decimals, but glow weight is based on the amount of protocol fees (USDC) that the farm paid
|
18699
|
-
* Therefore, the weight is based on the amount of USDC that was paid, which has 8 decimals
|
18700
|
-
*/
|
18701
|
-
const GLOW_WEIGHT_DECIMAL_PRECISION = 8;
|
18702
|
-
/**
|
18703
|
-
* @dev This is actually not as intuitive as it seems.
|
18704
|
-
* USDG weight is based on the amount of carbon credits produced, but the max value of a weight is ((2*64)-1) / 5 so we need to choose sensible precision to make sure that number never overflows
|
18705
|
-
*/
|
18706
|
-
const USDG_WEIGHT_DECIMAL_PRECISION = 8;
|
18707
|
-
const MAX_WEIGHT = (BigInt(2) ** BigInt(64) - BigInt(1)) / BigInt(5);
|
18708
|
-
|
18709
18695
|
const leafTypes = ["address", "uint256", "uint256"];
|
18710
18696
|
function hashLeaf({ address, glowWeight, usdcWeight, }) {
|
18711
18697
|
const hash = ethers.ethers.utils.solidityKeccak256(leafTypes, [
|
@@ -18723,14 +18709,14 @@ async function createWeeklyReportLegacy(args) {
|
|
18723
18709
|
const existingValue = map.get(key);
|
18724
18710
|
existingValue.glowWeight += value.glowWeight;
|
18725
18711
|
existingValue.usdgWeight += value.usdgWeight;
|
18726
|
-
if (existingValue.glowWeight > MAX_WEIGHT ||
|
18727
|
-
existingValue.usdgWeight > MAX_WEIGHT) {
|
18712
|
+
if (existingValue.glowWeight > useForwarder.MAX_WEIGHT ||
|
18713
|
+
existingValue.usdgWeight > useForwarder.MAX_WEIGHT) {
|
18728
18714
|
throw new Error(`Accumulated weight overflow on wallet ${key}`);
|
18729
18715
|
}
|
18730
18716
|
map.set(key, existingValue);
|
18731
18717
|
}
|
18732
18718
|
else {
|
18733
|
-
if (value.glowWeight > MAX_WEIGHT || value.usdgWeight > MAX_WEIGHT) {
|
18719
|
+
if (value.glowWeight > useForwarder.MAX_WEIGHT || value.usdgWeight > useForwarder.MAX_WEIGHT) {
|
18734
18720
|
throw new Error(`Initial weight overflow on wallet ${key}`);
|
18735
18721
|
}
|
18736
18722
|
map.set(key, value);
|
@@ -18759,10 +18745,10 @@ async function createWeeklyReportLegacy(args) {
|
|
18759
18745
|
if (Math.abs(sumOfRewardSplitsUSDGWeight - 1) > percentTolerance)
|
18760
18746
|
throw new Error(`USDG weight splits do not add up to 1 for farm ${farm.shortId}`);
|
18761
18747
|
for (const rewardSplit of farm.rewardSplits) {
|
18762
|
-
const glowBigInt = BigInt(viem.parseUnits(customToFixed(farm.weeklyPayment, GLOW_WEIGHT_DECIMAL_PRECISION), GLOW_WEIGHT_DECIMAL_PRECISION));
|
18763
|
-
const usdgBigInt = BigInt(viem.parseUnits(customToFixed(farm.carbonCreditsProduced, USDG_WEIGHT_DECIMAL_PRECISION), USDG_WEIGHT_DECIMAL_PRECISION));
|
18764
|
-
const glowWeight = multiplyBigIntByDecimalPercentage(glowBigInt, GLOW_WEIGHT_DECIMAL_PRECISION, rewardSplit.glowSplitPercent);
|
18765
|
-
const usdgWeight = multiplyBigIntByDecimalPercentage(usdgBigInt, USDG_WEIGHT_DECIMAL_PRECISION, rewardSplit.usdgSplitPercent);
|
18748
|
+
const glowBigInt = BigInt(viem.parseUnits(customToFixed(farm.weeklyPayment, useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION), useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION));
|
18749
|
+
const usdgBigInt = BigInt(viem.parseUnits(customToFixed(farm.carbonCreditsProduced, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION), useForwarder.USDG_WEIGHT_DECIMAL_PRECISION));
|
18750
|
+
const glowWeight = multiplyBigIntByDecimalPercentage(glowBigInt, useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION, rewardSplit.glowSplitPercent);
|
18751
|
+
const usdgWeight = multiplyBigIntByDecimalPercentage(usdgBigInt, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION, rewardSplit.usdgSplitPercent);
|
18766
18752
|
const value = {
|
18767
18753
|
wallet: rewardSplit.walletAddress,
|
18768
18754
|
glowWeight,
|
@@ -18807,10 +18793,10 @@ async function createWeeklyReportLegacy(args) {
|
|
18807
18793
|
const root = tree.getHexRoot();
|
18808
18794
|
const totalGlowWeightFinalizedLeavesSum = finalLeaves.reduce((acc, { glowWeight }) => acc.add(glowWeight), ethers.ethers.BigNumber.from(0));
|
18809
18795
|
const totalGCCWeightFinalizedLeavesSum = finalLeaves.reduce((acc, { usdgWeight }) => acc.add(usdgWeight), ethers.ethers.BigNumber.from(0));
|
18810
|
-
if (totalGlowWeightFinalizedLeavesSum.toBigInt() > MAX_WEIGHT) {
|
18796
|
+
if (totalGlowWeightFinalizedLeavesSum.toBigInt() > useForwarder.MAX_WEIGHT) {
|
18811
18797
|
throw new Error("Total glow weight is greater than max weight");
|
18812
18798
|
}
|
18813
|
-
if (totalGCCWeightFinalizedLeavesSum.toBigInt() > MAX_WEIGHT) {
|
18799
|
+
if (totalGCCWeightFinalizedLeavesSum.toBigInt() > useForwarder.MAX_WEIGHT) {
|
18814
18800
|
throw new Error("Total gcc weight is greater than max weight");
|
18815
18801
|
}
|
18816
18802
|
const headlineStats = {
|
@@ -18818,12 +18804,12 @@ async function createWeeklyReportLegacy(args) {
|
|
18818
18804
|
totalCreditsProduced: viem.formatUnits(totalCreditsProduced, 18),
|
18819
18805
|
totalCreditsProducedBN: totalCreditsProduced.toString(),
|
18820
18806
|
totalGlowWeightInFinalized: totalGlowWeightFinalizedLeavesSum.toString(),
|
18821
|
-
totalGlowWeightHuman: viem.formatUnits(BigInt(totalGlowWeightFinalizedLeavesSum.toString()), GLOW_WEIGHT_DECIMAL_PRECISION).toString(),
|
18807
|
+
totalGlowWeightHuman: viem.formatUnits(BigInt(totalGlowWeightFinalizedLeavesSum.toString()), useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION).toString(),
|
18822
18808
|
totalUSDGWeightInFinalized: totalGCCWeightFinalizedLeavesSum.toString(),
|
18823
|
-
totalUSDGWeightHuman: viem.formatUnits(BigInt(totalGCCWeightFinalizedLeavesSum.toString()), USDG_WEIGHT_DECIMAL_PRECISION).toString(),
|
18809
|
+
totalUSDGWeightHuman: viem.formatUnits(BigInt(totalGCCWeightFinalizedLeavesSum.toString()), useForwarder.USDG_WEIGHT_DECIMAL_PRECISION).toString(),
|
18824
18810
|
root: root,
|
18825
|
-
glowWeightDecimals: GLOW_WEIGHT_DECIMAL_PRECISION,
|
18826
|
-
usdgWeightDecimals: USDG_WEIGHT_DECIMAL_PRECISION,
|
18811
|
+
glowWeightDecimals: useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION,
|
18812
|
+
usdgWeightDecimals: useForwarder.USDG_WEIGHT_DECIMAL_PRECISION,
|
18827
18813
|
};
|
18828
18814
|
const farmsWithMerkleProofs = finalLeaves.map((leaf) => {
|
18829
18815
|
const hashedLeaf = hashLeaf({
|
@@ -18898,7 +18884,7 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
18898
18884
|
// Fetch active farms for the week (source of truth) and audits for the week.
|
18899
18885
|
const [apiResponse, auditsRes] = await Promise.all([
|
18900
18886
|
fetchFarmsForWeek(week, gcaUrls, apiUrl),
|
18901
|
-
axios.get(`${HUB_URL}/api/audits?omitDocuments=true&weekNumber=${week}`),
|
18887
|
+
axios.get(`${useForwarder.HUB_URL}/api/audits?omitDocuments=true&weekNumber=${week}`),
|
18902
18888
|
]);
|
18903
18889
|
const farms = apiResponse.filteredFarms; // List of farms active this week.
|
18904
18890
|
const audits = auditsRes.data; // Audits potentially containing adjusted credits.
|
@@ -18947,10 +18933,10 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
18947
18933
|
if (splitValue.isZero())
|
18948
18934
|
throw new Error(`Zero adjustedWeeklyCarbonCredit split for active farms in audit ${audit.id}`);
|
18949
18935
|
// Convert the decimal split value to a bigint using the defined precision.
|
18950
|
-
const splitBigInt = toBigInt(splitValue, USDG_WEIGHT_DECIMAL_PRECISION);
|
18936
|
+
const splitBigInt = toBigInt(splitValue, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION);
|
18951
18937
|
// Dust Check: Ensure that the conversion to bigint didn't truncate the value to zero.
|
18952
18938
|
if (splitBigInt === BigInt(0)) {
|
18953
|
-
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.`);
|
18939
|
+
throw new Error(`Adjusted credit split for audit ${audit.id} resulted in zero BigInt after conversion for precision ${useForwarder.USDG_WEIGHT_DECIMAL_PRECISION}. Original split value: ${splitValue.toString()}. This might indicate dust loss.`);
|
18954
18940
|
}
|
18955
18941
|
// Distribute the calculated split value to each active farm associated with this audit.
|
18956
18942
|
for (const sidString of auditActiveFarmSids) {
|
@@ -18994,7 +18980,7 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
18994
18980
|
if (Math.abs(sumUSDG - 1) > percentTolerance)
|
18995
18981
|
throw new Error(`USDG splits ≠1 for farm ${farm.shortId}`);
|
18996
18982
|
// Get the base GLOW payment for the farm, converted to bigint with appropriate precision.
|
18997
|
-
const glowBase = viem.parseUnits(customToFixed(farm.weeklyPayment, GLOW_WEIGHT_DECIMAL_PRECISION), GLOW_WEIGHT_DECIMAL_PRECISION);
|
18983
|
+
const glowBase = viem.parseUnits(customToFixed(farm.weeklyPayment, useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION), useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION);
|
18998
18984
|
// Retrieve the pre-calculated adjusted credit for this farm. Should always exist due to prior checks.
|
18999
18985
|
const adjustedCreditBigInt = shortIdToAdjustedCredit.get(String(farm.shortId)) ?? BigInt(0);
|
19000
18986
|
// Sanity check (likely redundant due to earlier checks, but safe).
|
@@ -19003,9 +18989,9 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19003
18989
|
// Process each reward split recipient for this farm.
|
19004
18990
|
for (const split of farm.rewardSplits) {
|
19005
18991
|
// Calculate the GLOW weight for this recipient based on the farm's weekly payment and split percentage.
|
19006
|
-
const glowWeight = multiplyBigIntByDecimalPercentage(glowBase, GLOW_WEIGHT_DECIMAL_PRECISION, split.glowSplitPercent);
|
18992
|
+
const glowWeight = multiplyBigIntByDecimalPercentage(glowBase, useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION, split.glowSplitPercent);
|
19007
18993
|
// Calculate the USDG weight for this recipient based on the farm's *adjusted* credit and split percentage.
|
19008
|
-
const usdgWeight = multiplyBigIntByDecimalPercentage(adjustedCreditBigInt, USDG_WEIGHT_DECIMAL_PRECISION, split.usdgSplitPercent);
|
18994
|
+
const usdgWeight = multiplyBigIntByDecimalPercentage(adjustedCreditBigInt, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION, split.usdgSplitPercent);
|
19009
18995
|
// Dust Loss Checks: Ensure non-zero percentages didn't result in zero weight due to precision limits.
|
19010
18996
|
if (split.usdgSplitPercent > 0 &&
|
19011
18997
|
adjustedCreditBigInt > BigInt(0) &&
|
@@ -19016,7 +19002,7 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19016
19002
|
glowWeight === BigInt(0))
|
19017
19003
|
throw new Error(`Glow dust lost for farm ${farm.shortId} wallet ${split.walletAddress}`);
|
19018
19004
|
// Overflow Check: Ensure individual leaf weights don't exceed the maximum allowed.
|
19019
|
-
if (glowWeight > MAX_WEIGHT || usdgWeight > MAX_WEIGHT)
|
19005
|
+
if (glowWeight > useForwarder.MAX_WEIGHT || usdgWeight > useForwarder.MAX_WEIGHT)
|
19020
19006
|
throw new Error(`Leaf weight overflow on wallet ${split.walletAddress}`);
|
19021
19007
|
// Accumulate the calculated weights into the map for the recipient wallet.
|
19022
19008
|
accumulateLeafWeights(split.walletAddress, { wallet: split.walletAddress, glowWeight, usdgWeight }, map);
|
@@ -19044,9 +19030,9 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19044
19030
|
const totalGlowWeight = finalizedLeaves.reduce((acc, { glowWeight }) => acc.add(glowWeight), ethers.ethers.BigNumber.from(0));
|
19045
19031
|
const totalUSDGWeight = finalizedLeaves.reduce((acc, { usdgWeight }) => acc.add(usdgWeight), ethers.ethers.BigNumber.from(0));
|
19046
19032
|
// Total Weight Overflow Checks: Ensure sums don't exceed maximum.
|
19047
|
-
if (totalGlowWeight.toBigInt() > MAX_WEIGHT)
|
19033
|
+
if (totalGlowWeight.toBigInt() > useForwarder.MAX_WEIGHT)
|
19048
19034
|
throw new Error("Total glow weight overflow");
|
19049
|
-
if (totalUSDGWeight.toBigInt() > MAX_WEIGHT)
|
19035
|
+
if (totalUSDGWeight.toBigInt() > useForwarder.MAX_WEIGHT)
|
19050
19036
|
throw new Error("Total USDG weight overflow");
|
19051
19037
|
// Generate Merkle proofs for each leaf and verify them.
|
19052
19038
|
const leavesWithProofs = finalizedLeaves.map((leaf) => {
|
@@ -19080,10 +19066,10 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19080
19066
|
// Calculate the total expected credits based on the adjusted values used.
|
19081
19067
|
const totalExpectedCredits = farms.reduce((acc, f) => {
|
19082
19068
|
const adj = shortIdToAdjustedCredit.get(String(f.shortId)) ?? BigInt(0);
|
19083
|
-
return acc.plus(fromBigInt(adj, USDG_WEIGHT_DECIMAL_PRECISION));
|
19069
|
+
return acc.plus(fromBigInt(adj, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION));
|
19084
19070
|
}, new Decimal(0));
|
19085
19071
|
// Convert total USDG weight back to human-readable decimal for deviation check.
|
19086
|
-
const totalUSDGWeightHuman = new Decimal(viem.formatUnits(BigInt(totalUSDGWeight.toString()), USDG_WEIGHT_DECIMAL_PRECISION));
|
19072
|
+
const totalUSDGWeightHuman = new Decimal(viem.formatUnits(BigInt(totalUSDGWeight.toString()), useForwarder.USDG_WEIGHT_DECIMAL_PRECISION));
|
19087
19073
|
// Check deviation between total adjusted credits used and the final sum of USDG weights.
|
19088
19074
|
if (greaterThanMaxDeviation(totalExpectedCredits.toNumber(), totalUSDGWeightHuman.toNumber(), 0.001 // 0.1% tolerance
|
19089
19075
|
)) {
|
@@ -19094,7 +19080,7 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19094
19080
|
throw new Error("totalExpectedCredits vs USDG weight deviation >0.1% ");
|
19095
19081
|
}
|
19096
19082
|
// Convert total Glow weight back to human-readable decimal.
|
19097
|
-
const totalGlowWeightHuman = new Decimal(viem.formatUnits(BigInt(totalGlowWeight.toString()), GLOW_WEIGHT_DECIMAL_PRECISION));
|
19083
|
+
const totalGlowWeightHuman = new Decimal(viem.formatUnits(BigInt(totalGlowWeight.toString()), useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION));
|
19098
19084
|
// Sum the original weekly protocol fee payments from farm data.
|
19099
19085
|
const totalProtocolFeePayments = farms.reduce((acc, f) => acc + f.weeklyPayment, 0);
|
19100
19086
|
// Check deviation between total glow weight and total protocol fees paid.
|
@@ -19117,18 +19103,18 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19117
19103
|
totalUSDGWeightInFinalized: totalUSDGWeight.toString(),
|
19118
19104
|
totalUSDGWeightHuman: totalUSDGWeightHuman.toString(),
|
19119
19105
|
root: merkleRoot,
|
19120
|
-
glowWeightDecimals: GLOW_WEIGHT_DECIMAL_PRECISION,
|
19121
|
-
usdgWeightDecimals: USDG_WEIGHT_DECIMAL_PRECISION,
|
19106
|
+
glowWeightDecimals: useForwarder.GLOW_WEIGHT_DECIMAL_PRECISION,
|
19107
|
+
usdgWeightDecimals: useForwarder.USDG_WEIGHT_DECIMAL_PRECISION,
|
19122
19108
|
};
|
19123
19109
|
// List of shortIds and their final adjusted credit value (human-readable).
|
19124
19110
|
const shortIdAdjustedList = Array.from(shortIdToAdjustedCredit.entries()).map(([shortId, creditBigInt]) => ({
|
19125
19111
|
shortId,
|
19126
|
-
adjustedCredit: fromBigInt(creditBigInt, USDG_WEIGHT_DECIMAL_PRECISION).toString(),
|
19112
|
+
adjustedCredit: fromBigInt(creditBigInt, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION).toString(),
|
19127
19113
|
}));
|
19128
19114
|
// Detailed comparison between originally reported credits and adjusted credits for each farm.
|
19129
19115
|
const creditsDeviationList = farms.map((farm) => {
|
19130
19116
|
const adj = shortIdToAdjustedCredit.get(String(farm.shortId)) ?? BigInt(0);
|
19131
|
-
const adjusted = fromBigInt(adj, USDG_WEIGHT_DECIMAL_PRECISION);
|
19117
|
+
const adjusted = fromBigInt(adj, useForwarder.USDG_WEIGHT_DECIMAL_PRECISION);
|
19132
19118
|
const produced = new Decimal(farm.carbonCreditsProduced);
|
19133
19119
|
let deviation;
|
19134
19120
|
let absDeviation;
|
@@ -19167,560 +19153,8 @@ async function createWeeklyReport({ week, gcaUrls, apiUrl, }) {
|
|
19167
19153
|
};
|
19168
19154
|
}
|
19169
19155
|
|
19170
|
-
|
19171
|
-
{
|
19172
|
-
inputs: [{ internalType: "address", name: "_forwarder", type: "address" }],
|
19173
|
-
stateMutability: "nonpayable",
|
19174
|
-
type: "constructor",
|
19175
|
-
},
|
19176
|
-
{
|
19177
|
-
inputs: [{ internalType: "address", name: "target", type: "address" }],
|
19178
|
-
name: "AddressEmptyCode",
|
19179
|
-
type: "error",
|
19180
|
-
},
|
19181
|
-
{
|
19182
|
-
inputs: [{ internalType: "address", name: "account", type: "address" }],
|
19183
|
-
name: "AddressInsufficientBalance",
|
19184
|
-
type: "error",
|
19185
|
-
},
|
19186
|
-
{ inputs: [], name: "FailedInnerCall", type: "error" },
|
19187
|
-
{
|
19188
|
-
inputs: [{ internalType: "address", name: "token", type: "address" }],
|
19189
|
-
name: "SafeERC20FailedOperation",
|
19190
|
-
type: "error",
|
19191
|
-
},
|
19192
|
-
{
|
19193
|
-
anonymous: false,
|
19194
|
-
inputs: [
|
19195
|
-
{ indexed: true, internalType: "address", name: "from", type: "address" },
|
19196
|
-
{ indexed: true, internalType: "address", name: "to", type: "address" },
|
19197
|
-
{
|
19198
|
-
indexed: true,
|
19199
|
-
internalType: "address",
|
19200
|
-
name: "token",
|
19201
|
-
type: "address",
|
19202
|
-
},
|
19203
|
-
{
|
19204
|
-
indexed: false,
|
19205
|
-
internalType: "uint256",
|
19206
|
-
name: "amount",
|
19207
|
-
type: "uint256",
|
19208
|
-
},
|
19209
|
-
{
|
19210
|
-
indexed: false,
|
19211
|
-
internalType: "string",
|
19212
|
-
name: "message",
|
19213
|
-
type: "string",
|
19214
|
-
},
|
19215
|
-
],
|
19216
|
-
name: "Forward",
|
19217
|
-
type: "event",
|
19218
|
-
},
|
19219
|
-
{
|
19220
|
-
inputs: [],
|
19221
|
-
name: "FORWARD_ADDRESS",
|
19222
|
-
outputs: [{ internalType: "address", name: "", type: "address" }],
|
19223
|
-
stateMutability: "view",
|
19224
|
-
type: "function",
|
19225
|
-
},
|
19226
|
-
{
|
19227
|
-
inputs: [
|
19228
|
-
{ internalType: "address", name: "token", type: "address" },
|
19229
|
-
{ internalType: "address", name: "to", type: "address" },
|
19230
|
-
{ internalType: "uint256", name: "amount", type: "uint256" },
|
19231
|
-
{ internalType: "string", name: "message", type: "string" },
|
19232
|
-
],
|
19233
|
-
name: "forward",
|
19234
|
-
outputs: [],
|
19235
|
-
stateMutability: "nonpayable",
|
19236
|
-
type: "function",
|
19237
|
-
},
|
19238
|
-
];
|
19239
|
-
|
19240
|
-
const ERC20_ABI = [
|
19241
|
-
{
|
19242
|
-
inputs: [
|
19243
|
-
{ name: "spender", type: "address" },
|
19244
|
-
{ name: "amount", type: "uint256" },
|
19245
|
-
],
|
19246
|
-
name: "approve",
|
19247
|
-
outputs: [{ name: "", type: "bool" }],
|
19248
|
-
stateMutability: "nonpayable",
|
19249
|
-
type: "function",
|
19250
|
-
},
|
19251
|
-
{
|
19252
|
-
inputs: [
|
19253
|
-
{ name: "owner", type: "address" },
|
19254
|
-
{ name: "spender", type: "address" },
|
19255
|
-
],
|
19256
|
-
name: "allowance",
|
19257
|
-
outputs: [{ name: "", type: "uint256" }],
|
19258
|
-
stateMutability: "view",
|
19259
|
-
type: "function",
|
19260
|
-
},
|
19261
|
-
{
|
19262
|
-
inputs: [
|
19263
|
-
{ name: "to", type: "address" },
|
19264
|
-
{ name: "amount", type: "uint256" },
|
19265
|
-
],
|
19266
|
-
name: "transfer",
|
19267
|
-
outputs: [{ name: "", type: "bool" }],
|
19268
|
-
stateMutability: "nonpayable",
|
19269
|
-
type: "function",
|
19270
|
-
},
|
19271
|
-
{
|
19272
|
-
inputs: [{ name: "account", type: "address" }],
|
19273
|
-
name: "balanceOf",
|
19274
|
-
outputs: [{ name: "", type: "uint256" }],
|
19275
|
-
stateMutability: "view",
|
19276
|
-
type: "function",
|
19277
|
-
},
|
19278
|
-
{
|
19279
|
-
inputs: [
|
19280
|
-
{ name: "account", type: "address" },
|
19281
|
-
{ name: "amount", type: "uint256" },
|
19282
|
-
],
|
19283
|
-
name: "mint",
|
19284
|
-
outputs: [{ name: "", type: "bool" }],
|
19285
|
-
stateMutability: "nonpayable",
|
19286
|
-
type: "function",
|
19287
|
-
},
|
19288
|
-
];
|
19289
|
-
|
19290
|
-
// Contract-specific addresses
|
19291
|
-
const mainnetAddresses = {
|
19292
|
-
USDG: "0xe010ec500720bE9EF3F82129E7eD2Ee1FB7955F2",
|
19293
|
-
GLW: "0xf4fbC617A5733EAAF9af08E1Ab816B103388d8B6",
|
19294
|
-
USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
19295
|
-
FORWARDER: "0x0000000000000000000000000000000000000000", // TODO: Update with actual mainnet address
|
19296
|
-
FOUNDATION_WALLET: "0x0000000000000000000000000000000000000000", // TODO: Update with actual mainnet foundation wallet
|
19297
|
-
};
|
19298
|
-
const sepoliaAddresses = {
|
19299
|
-
USDG: "0xda78313A3fF949890112c1B746AB1c75d1b1c17B",
|
19300
|
-
GLW: "0x2039161fcE4C8e5CF5FE64e17Fd290E8dFF3c9BD",
|
19301
|
-
USDC: "0x93c898be98cd2618ba84a6dccf5003d3bbe40356",
|
19302
|
-
FORWARDER: "0x9c1d61303D46BFAb1eC5F25c12A1Bf4cB3d06416",
|
19303
|
-
FOUNDATION_WALLET: "0x5e230FED487c86B90f6508104149F087d9B1B0A7",
|
19304
|
-
};
|
19305
|
-
const getAddresses = (CHAIN_ID) => {
|
19306
|
-
switch (CHAIN_ID) {
|
19307
|
-
case 1:
|
19308
|
-
return mainnetAddresses;
|
19309
|
-
case 11155111:
|
19310
|
-
return sepoliaAddresses;
|
19311
|
-
default:
|
19312
|
-
console.warn(`Unsupported chain ID: ${CHAIN_ID}, falling back to mainnet addresses`);
|
19313
|
-
return mainnetAddresses;
|
19314
|
-
}
|
19315
|
-
};
|
19316
|
-
|
19317
|
-
var ForwarderError;
|
19318
|
-
(function (ForwarderError) {
|
19319
|
-
ForwarderError["CONTRACT_NOT_AVAILABLE"] = "Contract not available";
|
19320
|
-
ForwarderError["SIGNER_NOT_AVAILABLE"] = "Signer not available";
|
19321
|
-
ForwarderError["UNKNOWN_ERROR"] = "Unknown error";
|
19322
|
-
ForwarderError["INVALID_FORWARD_TYPE"] = "Invalid forward type";
|
19323
|
-
ForwarderError["MISSING_REQUIRED_PARAMS"] = "Missing required parameters";
|
19324
|
-
})(ForwarderError || (ForwarderError = {}));
|
19325
|
-
// Utility to extract the most useful revert reason from an ethers error object
|
19326
|
-
function parseEthersError(error) {
|
19327
|
-
if (!error)
|
19328
|
-
return "Unknown error";
|
19329
|
-
const possibleError = error;
|
19330
|
-
// If the error originates from a callStatic it will often be found at `error?.error?.body`
|
19331
|
-
if (possibleError?.error?.body) {
|
19332
|
-
try {
|
19333
|
-
const body = JSON.parse(possibleError.error.body);
|
19334
|
-
// Hardhat style errors
|
19335
|
-
if (body?.error?.message)
|
19336
|
-
return body.error.message;
|
19337
|
-
}
|
19338
|
-
catch { }
|
19339
|
-
}
|
19340
|
-
// Found on MetaMask/Alchemy shape errors
|
19341
|
-
if (possibleError?.data?.message)
|
19342
|
-
return possibleError.data.message;
|
19343
|
-
if (possibleError?.error?.message)
|
19344
|
-
return possibleError.error.message;
|
19345
|
-
// Standard ethers v5 message
|
19346
|
-
if (possibleError?.reason)
|
19347
|
-
return possibleError.reason;
|
19348
|
-
if (possibleError?.message)
|
19349
|
-
return possibleError.message;
|
19350
|
-
return ForwarderError.UNKNOWN_ERROR;
|
19351
|
-
}
|
19352
|
-
// Type-guard style helper to ensure a signer exists throughout the rest of the function.
|
19353
|
-
function assertSigner(maybeSigner) {
|
19354
|
-
if (!maybeSigner) {
|
19355
|
-
throw new Error(ForwarderError.SIGNER_NOT_AVAILABLE);
|
19356
|
-
}
|
19357
|
-
}
|
19358
|
-
function useForwarder(signer, CHAIN_ID) {
|
19359
|
-
// Use dynamic addresses based on chain configuration
|
19360
|
-
const ADDRESSES = getAddresses(CHAIN_ID);
|
19361
|
-
// Framework-agnostic processing flag
|
19362
|
-
let isProcessing = false;
|
19363
|
-
const setIsProcessing = (value) => {
|
19364
|
-
isProcessing = value;
|
19365
|
-
};
|
19366
|
-
// Returns a contract instance for Forwarder
|
19367
|
-
function getForwarderContract() {
|
19368
|
-
assertSigner(signer);
|
19369
|
-
return new ethers.ethers.Contract(ADDRESSES.FORWARDER, FORWARDER_ABI, signer);
|
19370
|
-
}
|
19371
|
-
/**
|
19372
|
-
* Construct the message for the forward call based on type and parameters
|
19373
|
-
*/
|
19374
|
-
function constructForwardMessage(params) {
|
19375
|
-
const { type, applicationId, farmId, regionId, userAddress } = params;
|
19376
|
-
switch (type) {
|
19377
|
-
case "PayProtocolFeeAndMintGCTLAndStake":
|
19378
|
-
if (!applicationId) {
|
19379
|
-
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19380
|
-
}
|
19381
|
-
return `PayProtocolFeeAndMintGCTLAndStake::${applicationId}`;
|
19382
|
-
case "PayProtocolFee":
|
19383
|
-
if (!applicationId) {
|
19384
|
-
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19385
|
-
}
|
19386
|
-
return `PayProtocolFee::${applicationId}`;
|
19387
|
-
case "MintGCTLAndStake":
|
19388
|
-
if (!regionId) {
|
19389
|
-
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19390
|
-
}
|
19391
|
-
return `MintGCTLAndStake::${regionId}`;
|
19392
|
-
case "MintGCTL":
|
19393
|
-
if (!userAddress) {
|
19394
|
-
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19395
|
-
}
|
19396
|
-
return `MintGCTL::${userAddress}`;
|
19397
|
-
case "BuySolarFarm":
|
19398
|
-
if (!farmId) {
|
19399
|
-
throw new Error(ForwarderError.MISSING_REQUIRED_PARAMS);
|
19400
|
-
}
|
19401
|
-
return `BuySolarFarm::${farmId}`;
|
19402
|
-
default:
|
19403
|
-
throw new Error(ForwarderError.INVALID_FORWARD_TYPE);
|
19404
|
-
}
|
19405
|
-
}
|
19406
|
-
/**
|
19407
|
-
* Get the appropriate token contract based on currency
|
19408
|
-
*/
|
19409
|
-
function getTokenContract(currency = "USDC") {
|
19410
|
-
assertSigner(signer);
|
19411
|
-
let tokenAddress;
|
19412
|
-
switch (currency) {
|
19413
|
-
case "USDC":
|
19414
|
-
tokenAddress = ADDRESSES.USDC;
|
19415
|
-
break;
|
19416
|
-
case "GLW":
|
19417
|
-
tokenAddress = ADDRESSES.GLW;
|
19418
|
-
break;
|
19419
|
-
case "USDG":
|
19420
|
-
tokenAddress = ADDRESSES.USDG;
|
19421
|
-
break;
|
19422
|
-
default:
|
19423
|
-
throw new Error(`Currency ${currency} not yet supported. Only USDC, GLW, and USDG are currently supported.`);
|
19424
|
-
}
|
19425
|
-
return new ethers.ethers.Contract(tokenAddress, ERC20_ABI, signer);
|
19426
|
-
}
|
19427
|
-
/**
|
19428
|
-
* Check current token allowance for the forwarder contract
|
19429
|
-
* @param owner The wallet address to check allowance for
|
19430
|
-
* @param currency The currency to check allowance for
|
19431
|
-
*/
|
19432
|
-
async function checkTokenAllowance(owner, currency = "USDC") {
|
19433
|
-
assertSigner(signer);
|
19434
|
-
try {
|
19435
|
-
const tokenContract = getTokenContract(currency);
|
19436
|
-
if (!tokenContract)
|
19437
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19438
|
-
const allowance = await tokenContract.allowance(owner, ADDRESSES.FORWARDER);
|
19439
|
-
return allowance;
|
19440
|
-
}
|
19441
|
-
catch (error) {
|
19442
|
-
throw new Error(parseEthersError(error));
|
19443
|
-
}
|
19444
|
-
}
|
19445
|
-
/**
|
19446
|
-
* Check user's token balance
|
19447
|
-
* @param owner The wallet address to check balance for
|
19448
|
-
* @param currency The currency to check balance for
|
19449
|
-
*/
|
19450
|
-
async function checkTokenBalance(owner, currency = "USDC") {
|
19451
|
-
assertSigner(signer);
|
19452
|
-
try {
|
19453
|
-
const tokenContract = getTokenContract(currency);
|
19454
|
-
if (!tokenContract)
|
19455
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19456
|
-
const balance = await tokenContract.balanceOf(owner);
|
19457
|
-
return balance;
|
19458
|
-
}
|
19459
|
-
catch (error) {
|
19460
|
-
throw new Error(parseEthersError(error));
|
19461
|
-
}
|
19462
|
-
}
|
19463
|
-
/**
|
19464
|
-
* Approve tokens for the forwarder contract
|
19465
|
-
* @param amount Amount to approve (BigNumber)
|
19466
|
-
* @param currency The currency to approve
|
19467
|
-
*/
|
19468
|
-
async function approveToken(amount, currency = "USDC") {
|
19469
|
-
assertSigner(signer);
|
19470
|
-
try {
|
19471
|
-
const tokenContract = getTokenContract(currency);
|
19472
|
-
if (!tokenContract)
|
19473
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19474
|
-
setIsProcessing(true);
|
19475
|
-
// Approve only the specific amount needed
|
19476
|
-
const approveTx = await tokenContract.approve(ADDRESSES.FORWARDER, amount);
|
19477
|
-
await approveTx.wait();
|
19478
|
-
return true;
|
19479
|
-
}
|
19480
|
-
catch (error) {
|
19481
|
-
throw new Error(parseEthersError(error));
|
19482
|
-
}
|
19483
|
-
finally {
|
19484
|
-
setIsProcessing(false);
|
19485
|
-
}
|
19486
|
-
}
|
19487
|
-
/**
|
19488
|
-
* Forward tokens through the forwarder contract with type-specific handling
|
19489
|
-
* @param params Forward parameters including type, amount, and required fields
|
19490
|
-
*/
|
19491
|
-
async function forwardTokens(params) {
|
19492
|
-
assertSigner(signer);
|
19493
|
-
try {
|
19494
|
-
const forwarderContract = getForwarderContract();
|
19495
|
-
if (!forwarderContract)
|
19496
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19497
|
-
setIsProcessing(true);
|
19498
|
-
const { amount, currency = "USDC" } = params;
|
19499
|
-
const tokenContract = getTokenContract(currency);
|
19500
|
-
if (!tokenContract)
|
19501
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19502
|
-
const owner = await signer.getAddress();
|
19503
|
-
// Construct the appropriate message for this forward type
|
19504
|
-
const message = constructForwardMessage(params);
|
19505
|
-
// Check allowance and approve if necessary
|
19506
|
-
const allowance = await tokenContract.allowance(owner, ADDRESSES.FORWARDER);
|
19507
|
-
if (allowance.lt(amount)) {
|
19508
|
-
try {
|
19509
|
-
const approveTx = await tokenContract.approve(ADDRESSES.FORWARDER, ethers.ethers.constants.MaxUint256);
|
19510
|
-
await approveTx.wait();
|
19511
|
-
}
|
19512
|
-
catch (approveError) {
|
19513
|
-
throw new Error(parseEthersError(approveError) || "Token approval failed");
|
19514
|
-
}
|
19515
|
-
}
|
19516
|
-
// Get the token address based on currency
|
19517
|
-
let tokenAddress;
|
19518
|
-
switch (currency) {
|
19519
|
-
case "USDC":
|
19520
|
-
tokenAddress = ADDRESSES.USDC;
|
19521
|
-
break;
|
19522
|
-
case "USDG":
|
19523
|
-
tokenAddress = ADDRESSES.USDG;
|
19524
|
-
break;
|
19525
|
-
case "GLW":
|
19526
|
-
tokenAddress = ADDRESSES.GLW;
|
19527
|
-
break;
|
19528
|
-
default:
|
19529
|
-
throw new Error(`Unsupported currency for forwarding: ${currency}`);
|
19530
|
-
}
|
19531
|
-
// Run a static call first to surface any revert reason
|
19532
|
-
try {
|
19533
|
-
await forwarderContract.callStatic.forward(tokenAddress, ADDRESSES.FOUNDATION_WALLET, amount, message, { from: owner });
|
19534
|
-
}
|
19535
|
-
catch (staticError) {
|
19536
|
-
throw new Error(parseEthersError(staticError));
|
19537
|
-
}
|
19538
|
-
// Execute the forward transaction
|
19539
|
-
const tx = await forwarderContract.forward(tokenAddress, ADDRESSES.FOUNDATION_WALLET, amount, message);
|
19540
|
-
await tx.wait();
|
19541
|
-
return tx.hash;
|
19542
|
-
}
|
19543
|
-
catch (txError) {
|
19544
|
-
throw new Error(parseEthersError(txError));
|
19545
|
-
}
|
19546
|
-
finally {
|
19547
|
-
setIsProcessing(false);
|
19548
|
-
}
|
19549
|
-
}
|
19550
|
-
/**
|
19551
|
-
* Forward tokens for protocol fee payment and GCTL minting with staking
|
19552
|
-
*/
|
19553
|
-
async function payProtocolFeeAndMintGCTLAndStake(amount, userAddress, applicationId, regionId, currency = "USDC") {
|
19554
|
-
assertSigner(signer);
|
19555
|
-
// GCTL minting only supports USDC and USDG
|
19556
|
-
if (currency === "GLW") {
|
19557
|
-
throw new Error("GCTL minting is not supported with GLW payment. Use USDC or USDG.");
|
19558
|
-
}
|
19559
|
-
return forwardTokens({
|
19560
|
-
amount,
|
19561
|
-
userAddress,
|
19562
|
-
type: "PayProtocolFeeAndMintGCTLAndStake",
|
19563
|
-
currency,
|
19564
|
-
applicationId,
|
19565
|
-
regionId,
|
19566
|
-
});
|
19567
|
-
}
|
19568
|
-
/**
|
19569
|
-
* Forward tokens for protocol fee payment only
|
19570
|
-
*/
|
19571
|
-
async function payProtocolFee(amount, userAddress, applicationId, currency = "USDC") {
|
19572
|
-
assertSigner(signer);
|
19573
|
-
return forwardTokens({
|
19574
|
-
amount,
|
19575
|
-
userAddress,
|
19576
|
-
type: "PayProtocolFee",
|
19577
|
-
currency,
|
19578
|
-
applicationId,
|
19579
|
-
});
|
19580
|
-
}
|
19581
|
-
/**
|
19582
|
-
* Forward USDC to mint GCTL and stake to a region
|
19583
|
-
*/
|
19584
|
-
async function mintGCTLAndStake(amount, userAddress, regionId) {
|
19585
|
-
assertSigner(signer);
|
19586
|
-
return forwardTokens({
|
19587
|
-
amount,
|
19588
|
-
userAddress,
|
19589
|
-
type: "MintGCTLAndStake",
|
19590
|
-
currency: "USDC",
|
19591
|
-
regionId,
|
19592
|
-
});
|
19593
|
-
}
|
19594
|
-
/**
|
19595
|
-
* Forward USDC to mint GCTL (existing functionality, keeping for compatibility)
|
19596
|
-
*/
|
19597
|
-
async function mintGCTL(amount, userAddress) {
|
19598
|
-
assertSigner(signer);
|
19599
|
-
return forwardTokens({
|
19600
|
-
amount,
|
19601
|
-
userAddress,
|
19602
|
-
type: "MintGCTL",
|
19603
|
-
currency: "USDC",
|
19604
|
-
});
|
19605
|
-
}
|
19606
|
-
/**
|
19607
|
-
* Forward tokens to buy a solar farm
|
19608
|
-
*/
|
19609
|
-
async function buySolarFarm(amount, userAddress, farmId, currency = "USDC") {
|
19610
|
-
assertSigner(signer);
|
19611
|
-
return forwardTokens({
|
19612
|
-
amount,
|
19613
|
-
userAddress,
|
19614
|
-
type: "BuySolarFarm",
|
19615
|
-
currency,
|
19616
|
-
farmId,
|
19617
|
-
});
|
19618
|
-
}
|
19619
|
-
/**
|
19620
|
-
* Estimate gas for forwarding with type-specific handling
|
19621
|
-
* @param params Forward parameters
|
19622
|
-
* @param ethPriceInUSD Current ETH price in USD (for cost estimation)
|
19623
|
-
*/
|
19624
|
-
async function estimateGasForForward(params, ethPriceInUSD) {
|
19625
|
-
assertSigner(signer);
|
19626
|
-
try {
|
19627
|
-
const forwarderContract = getForwarderContract();
|
19628
|
-
if (!forwarderContract)
|
19629
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19630
|
-
const { amount, currency = "USDC" } = params;
|
19631
|
-
// Construct the appropriate message for this forward type
|
19632
|
-
const message = constructForwardMessage(params);
|
19633
|
-
// Get token address
|
19634
|
-
let tokenAddress;
|
19635
|
-
switch (currency) {
|
19636
|
-
case "USDC":
|
19637
|
-
tokenAddress = ADDRESSES.USDC;
|
19638
|
-
break;
|
19639
|
-
case "USDG":
|
19640
|
-
tokenAddress = ADDRESSES.USDG;
|
19641
|
-
break;
|
19642
|
-
case "GLW":
|
19643
|
-
tokenAddress = ADDRESSES.GLW;
|
19644
|
-
break;
|
19645
|
-
default:
|
19646
|
-
throw new Error(`Unsupported currency for gas estimation: ${currency}`);
|
19647
|
-
}
|
19648
|
-
const gasPrice = await signer.getGasPrice();
|
19649
|
-
const estimatedGas = await forwarderContract.estimateGas.forward(tokenAddress, ADDRESSES.FOUNDATION_WALLET, amount, message);
|
19650
|
-
const estimatedCost = estimatedGas.mul(gasPrice);
|
19651
|
-
if (ethPriceInUSD) {
|
19652
|
-
const estimatedCostInEth = ethers.ethers.utils.formatEther(estimatedCost);
|
19653
|
-
const estimatedCostInUSD = (parseFloat(estimatedCostInEth) * ethPriceInUSD).toFixed(2);
|
19654
|
-
return estimatedCostInUSD;
|
19655
|
-
}
|
19656
|
-
else {
|
19657
|
-
throw new Error("Could not fetch the ETH price to calculate cost in USD.");
|
19658
|
-
}
|
19659
|
-
}
|
19660
|
-
catch (error) {
|
19661
|
-
throw new Error(parseEthersError(error));
|
19662
|
-
}
|
19663
|
-
}
|
19664
|
-
/**
|
19665
|
-
* Mint test USDC (only works on testnets with mintable USDC contracts)
|
19666
|
-
* @param amount Amount of USDC to mint (BigNumber, 6 decimals)
|
19667
|
-
* @param recipient Address to mint USDC to
|
19668
|
-
*/
|
19669
|
-
async function mintTestUSDC(amount, recipient) {
|
19670
|
-
assertSigner(signer);
|
19671
|
-
if (CHAIN_ID !== 11155111) {
|
19672
|
-
throw new Error("Minting test USDC is only supported on Sepolia");
|
19673
|
-
}
|
19674
|
-
try {
|
19675
|
-
const usdcContract = getTokenContract("USDC"); // Use getTokenContract for consistency
|
19676
|
-
if (!usdcContract)
|
19677
|
-
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
19678
|
-
setIsProcessing(true);
|
19679
|
-
// Try to call mint function (common for test tokens)
|
19680
|
-
const tx = await usdcContract.mint(recipient, amount);
|
19681
|
-
await tx.wait();
|
19682
|
-
return tx.hash;
|
19683
|
-
}
|
19684
|
-
catch (error) {
|
19685
|
-
// If mint function doesn't exist or fails, provide helpful error
|
19686
|
-
const errorMessage = parseEthersError(error);
|
19687
|
-
if (errorMessage.includes("mint")) {
|
19688
|
-
throw new Error("This USDC contract doesn't support minting");
|
19689
|
-
}
|
19690
|
-
throw new Error(errorMessage);
|
19691
|
-
}
|
19692
|
-
finally {
|
19693
|
-
setIsProcessing(false);
|
19694
|
-
}
|
19695
|
-
}
|
19696
|
-
return {
|
19697
|
-
// New methods for different forward types
|
19698
|
-
forwardTokens,
|
19699
|
-
payProtocolFeeAndMintGCTLAndStake,
|
19700
|
-
payProtocolFee,
|
19701
|
-
mintGCTLAndStake,
|
19702
|
-
mintGCTL,
|
19703
|
-
buySolarFarm,
|
19704
|
-
// Token operations
|
19705
|
-
approveToken,
|
19706
|
-
checkTokenAllowance,
|
19707
|
-
checkTokenBalance,
|
19708
|
-
// Utility methods
|
19709
|
-
estimateGasForForward,
|
19710
|
-
mintTestUSDC,
|
19711
|
-
constructForwardMessage,
|
19712
|
-
// State
|
19713
|
-
get isProcessing() {
|
19714
|
-
return isProcessing;
|
19715
|
-
},
|
19716
|
-
addresses: ADDRESSES,
|
19717
|
-
// Signer availability
|
19718
|
-
isSignerAvailable: !!signer,
|
19719
|
-
};
|
19720
|
-
}
|
19721
|
-
|
19156
|
+
exports.useForwarder = useForwarder.useForwarder;
|
19722
19157
|
exports.GENESIS_TIMESTAMP = GENESIS_TIMESTAMP;
|
19723
19158
|
exports.createWeeklyReport = createWeeklyReport;
|
19724
19159
|
exports.createWeeklyReportLegacy = createWeeklyReportLegacy;
|
19725
|
-
exports.useForwarder = useForwarder;
|
19726
19160
|
//# sourceMappingURL=index.js.map
|