@glowlabs-org/utils 0.2.23 → 0.2.26
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 +1 -1
- package/dist/cjs/index.js +25 -25
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/control-api/region-router.d.ts +5 -1
- package/dist/cjs/lib/hooks/use-forwarder.d.ts +13 -13
- package/dist/cjs/lib/types/index.d.ts +50 -0
- package/dist/cjs/{region-router-DZPbuGxv.js → region-router-CIjrTHtv.js} +73 -17
- package/dist/cjs/region-router-CIjrTHtv.js.map +1 -0
- package/dist/esm/browser.js +1 -1
- package/dist/esm/index.js +27 -27
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/control-api/region-router.d.ts +5 -1
- package/dist/esm/lib/hooks/use-forwarder.d.ts +13 -13
- package/dist/esm/lib/types/index.d.ts +50 -0
- package/dist/esm/{region-router-BE9kP_sl.js → region-router-CSTfHLOs.js} +74 -18
- package/dist/esm/region-router-CSTfHLOs.js.map +1 -0
- package/package.json +3 -3
- package/src/lib/control-api/region-router.ts +59 -0
- package/src/lib/create-weekly-report/index.ts +30 -40
- package/src/lib/create-weekly-report/utils/hashLeaf.ts +2 -2
- package/src/lib/hooks/use-forwarder.ts +61 -60
- package/src/lib/types/index.ts +64 -0
- package/src/utils/hash-leaf.ts +2 -2
- package/dist/cjs/region-router-DZPbuGxv.js.map +0 -1
- package/dist/esm/region-router-BE9kP_sl.js.map +0 -1
|
@@ -6,6 +6,10 @@ import type {
|
|
|
6
6
|
RegionWithMetadata,
|
|
7
7
|
ActivationConfig,
|
|
8
8
|
CreateRegionPayload,
|
|
9
|
+
CreateKickstarterPayload,
|
|
10
|
+
Kickstarter,
|
|
11
|
+
ActivationEvent,
|
|
12
|
+
KickstarterCreateResponse,
|
|
9
13
|
} from "../types";
|
|
10
14
|
|
|
11
15
|
// ---------------------------------------------------------------------------
|
|
@@ -41,6 +45,7 @@ export function RegionRouter(baseUrl: string) {
|
|
|
41
45
|
let cachedRegions: Region[] = [];
|
|
42
46
|
let isLoading = false;
|
|
43
47
|
let isCreatingRegion = false;
|
|
48
|
+
let isCreatingKickstarter = false;
|
|
44
49
|
|
|
45
50
|
// -------------------------------------------------------------------------
|
|
46
51
|
// Queries
|
|
@@ -70,6 +75,20 @@ export function RegionRouter(baseUrl: string) {
|
|
|
70
75
|
}
|
|
71
76
|
};
|
|
72
77
|
|
|
78
|
+
const fetchActivationEvents = async (
|
|
79
|
+
regionId?: number
|
|
80
|
+
): Promise<ActivationEvent[]> => {
|
|
81
|
+
try {
|
|
82
|
+
const query = typeof regionId === "number" ? `?regionId=${regionId}` : "";
|
|
83
|
+
const data = await request<{ events: ActivationEvent[] }>(
|
|
84
|
+
`/regions/activation-events${query}`
|
|
85
|
+
);
|
|
86
|
+
return data.events ?? [];
|
|
87
|
+
} catch (error) {
|
|
88
|
+
throw new Error(parseApiError(error));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
73
92
|
// -------------------------------------------------------------------------
|
|
74
93
|
// Mutations
|
|
75
94
|
// -------------------------------------------------------------------------
|
|
@@ -90,6 +109,40 @@ export function RegionRouter(baseUrl: string) {
|
|
|
90
109
|
}
|
|
91
110
|
};
|
|
92
111
|
|
|
112
|
+
const createKickstarter = async (
|
|
113
|
+
payload: CreateKickstarterPayload
|
|
114
|
+
): Promise<KickstarterCreateResponse> => {
|
|
115
|
+
isCreatingKickstarter = true;
|
|
116
|
+
try {
|
|
117
|
+
const data = await request<KickstarterCreateResponse>(
|
|
118
|
+
`/regions/kickstarters`,
|
|
119
|
+
{
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "Content-Type": "application/json" },
|
|
122
|
+
body: JSON.stringify(payload),
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
// A new region may have been created; refresh regions cache
|
|
126
|
+
await fetchRegions();
|
|
127
|
+
return data;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
throw new Error(parseApiError(error));
|
|
130
|
+
} finally {
|
|
131
|
+
isCreatingKickstarter = false;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const fetchKickstarter = async (idOrSlug: string): Promise<Kickstarter> => {
|
|
136
|
+
try {
|
|
137
|
+
const data = await request<{ kickstarter: Kickstarter }>(
|
|
138
|
+
`/regions/kickstarters/${encodeURIComponent(idOrSlug)}`
|
|
139
|
+
);
|
|
140
|
+
return data.kickstarter;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
throw new Error(parseApiError(error));
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
93
146
|
// -------------------------------------------------------------------------
|
|
94
147
|
// Helpers (derived)
|
|
95
148
|
// -------------------------------------------------------------------------
|
|
@@ -136,8 +189,11 @@ export function RegionRouter(baseUrl: string) {
|
|
|
136
189
|
// Data access
|
|
137
190
|
fetchRegions,
|
|
138
191
|
fetchActivationConfig,
|
|
192
|
+
fetchActivationEvents,
|
|
193
|
+
fetchKickstarter,
|
|
139
194
|
getRegionByCode,
|
|
140
195
|
createRegion,
|
|
196
|
+
createKickstarter,
|
|
141
197
|
|
|
142
198
|
// Cached data & flags
|
|
143
199
|
get regions() {
|
|
@@ -149,5 +205,8 @@ export function RegionRouter(baseUrl: string) {
|
|
|
149
205
|
get isCreatingRegion() {
|
|
150
206
|
return isCreatingRegion;
|
|
151
207
|
},
|
|
208
|
+
get isCreatingKickstarter() {
|
|
209
|
+
return isCreatingKickstarter;
|
|
210
|
+
},
|
|
152
211
|
} as const;
|
|
153
212
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { formatUnits, parseUnits } from "viem";
|
|
3
3
|
import { MerkleTree } from "merkletreejs";
|
|
4
|
-
import {
|
|
4
|
+
import { keccak256 } from "ethers";
|
|
5
5
|
import { greaterThanMaxDeviation } from "./utils/greater-than-max-deviation";
|
|
6
6
|
import { customToFixed } from "./utils/custom-to-fixed";
|
|
7
7
|
import { HUB_URL } from "../../constants/urls";
|
|
@@ -202,22 +202,22 @@ export async function createWeeklyReportLegacy(args: CreateWeeklyReportArgs) {
|
|
|
202
202
|
})
|
|
203
203
|
);
|
|
204
204
|
|
|
205
|
-
const tree = new MerkleTree(leaves,
|
|
205
|
+
const tree = new MerkleTree(leaves, keccak256, { sort: true });
|
|
206
206
|
const root = tree.getHexRoot();
|
|
207
207
|
|
|
208
208
|
const totalGlowWeightFinalizedLeavesSum = finalLeaves.reduce(
|
|
209
|
-
(acc, { glowWeight }) => acc
|
|
210
|
-
|
|
209
|
+
(acc, { glowWeight }) => acc + BigInt(glowWeight),
|
|
210
|
+
0n
|
|
211
211
|
);
|
|
212
212
|
const totalGCCWeightFinalizedLeavesSum = finalLeaves.reduce(
|
|
213
|
-
(acc, { usdgWeight }) => acc
|
|
214
|
-
|
|
213
|
+
(acc, { usdgWeight }) => acc + BigInt(usdgWeight),
|
|
214
|
+
0n
|
|
215
215
|
);
|
|
216
216
|
|
|
217
|
-
if (totalGlowWeightFinalizedLeavesSum
|
|
217
|
+
if (totalGlowWeightFinalizedLeavesSum > MAX_WEIGHT) {
|
|
218
218
|
throw new Error("Total glow weight is greater than max weight");
|
|
219
219
|
}
|
|
220
|
-
if (totalGCCWeightFinalizedLeavesSum
|
|
220
|
+
if (totalGCCWeightFinalizedLeavesSum > MAX_WEIGHT) {
|
|
221
221
|
throw new Error("Total gcc weight is greater than max weight");
|
|
222
222
|
}
|
|
223
223
|
|
|
@@ -257,14 +257,12 @@ export async function createWeeklyReportLegacy(args: CreateWeeklyReportArgs) {
|
|
|
257
257
|
};
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
-
let forLoopedGlowWeightSum
|
|
260
|
+
let forLoopedGlowWeightSum = 0n;
|
|
261
261
|
for (const leafProof of farmsWithMerkleProofs) {
|
|
262
|
-
forLoopedGlowWeightSum
|
|
263
|
-
BigNumber.from(leafProof.glowWeight)
|
|
264
|
-
);
|
|
262
|
+
forLoopedGlowWeightSum += BigInt(leafProof.glowWeight);
|
|
265
263
|
}
|
|
266
264
|
|
|
267
|
-
if (
|
|
265
|
+
if (forLoopedGlowWeightSum !== totalGlowWeightFinalizedLeavesSum) {
|
|
268
266
|
console.error("Glow Weight Sum Mismatch:");
|
|
269
267
|
console.error("Sum from loop:", forLoopedGlowWeightSum.toString());
|
|
270
268
|
console.error(
|
|
@@ -274,14 +272,12 @@ export async function createWeeklyReportLegacy(args: CreateWeeklyReportArgs) {
|
|
|
274
272
|
throw new Error("Glow weight sum is not equal");
|
|
275
273
|
}
|
|
276
274
|
|
|
277
|
-
let forLoopedGCCWeightSum
|
|
275
|
+
let forLoopedGCCWeightSum = 0n;
|
|
278
276
|
for (const leafProof of farmsWithMerkleProofs) {
|
|
279
|
-
forLoopedGCCWeightSum
|
|
280
|
-
BigNumber.from(leafProof.usdgWeight)
|
|
281
|
-
);
|
|
277
|
+
forLoopedGCCWeightSum += BigInt(leafProof.usdgWeight);
|
|
282
278
|
}
|
|
283
279
|
|
|
284
|
-
if (
|
|
280
|
+
if (forLoopedGCCWeightSum !== totalGCCWeightFinalizedLeavesSum) {
|
|
285
281
|
console.error("USDG Weight Sum Mismatch:");
|
|
286
282
|
console.error("Sum from loop:", forLoopedGCCWeightSum.toString());
|
|
287
283
|
console.error(
|
|
@@ -597,25 +593,25 @@ export async function createWeeklyReport({
|
|
|
597
593
|
);
|
|
598
594
|
|
|
599
595
|
// Build the Merkle tree.
|
|
600
|
-
const merkleTree = new MerkleTree(hashedLeaves,
|
|
596
|
+
const merkleTree = new MerkleTree(hashedLeaves, keccak256, {
|
|
601
597
|
sort: true, // Ensure consistent tree structure.
|
|
602
598
|
});
|
|
603
599
|
const merkleRoot = merkleTree.getHexRoot(); // Get the root hash.
|
|
604
600
|
|
|
605
601
|
// Calculate the total weights across all finalized leaves.
|
|
606
602
|
const totalGlowWeight = finalizedLeaves.reduce(
|
|
607
|
-
(acc, { glowWeight }) => acc
|
|
608
|
-
|
|
603
|
+
(acc, { glowWeight }) => acc + BigInt(glowWeight),
|
|
604
|
+
0n
|
|
609
605
|
);
|
|
610
606
|
const totalUSDGWeight = finalizedLeaves.reduce(
|
|
611
|
-
(acc, { usdgWeight }) => acc
|
|
612
|
-
|
|
607
|
+
(acc, { usdgWeight }) => acc + BigInt(usdgWeight),
|
|
608
|
+
0n
|
|
613
609
|
);
|
|
614
610
|
|
|
615
611
|
// Total Weight Overflow Checks: Ensure sums don't exceed maximum.
|
|
616
|
-
if (totalGlowWeight
|
|
612
|
+
if (totalGlowWeight > MAX_WEIGHT)
|
|
617
613
|
throw new Error("Total glow weight overflow");
|
|
618
|
-
if (totalUSDGWeight
|
|
614
|
+
if (totalUSDGWeight > MAX_WEIGHT)
|
|
619
615
|
throw new Error("Total USDG weight overflow");
|
|
620
616
|
|
|
621
617
|
// Generate Merkle proofs for each leaf and verify them.
|
|
@@ -636,10 +632,10 @@ export async function createWeeklyReport({
|
|
|
636
632
|
|
|
637
633
|
// Verify that summing weights from leavesWithProofs matches the earlier reduce calculation.
|
|
638
634
|
const glowSumProofLoop = leavesWithProofs.reduce(
|
|
639
|
-
(acc, l) => acc
|
|
640
|
-
|
|
635
|
+
(acc, l) => acc + BigInt(l.glowWeight),
|
|
636
|
+
0n
|
|
641
637
|
);
|
|
642
|
-
if (
|
|
638
|
+
if (glowSumProofLoop !== totalGlowWeight) {
|
|
643
639
|
console.error("Glow Weight Sum Mismatch (Post-73):");
|
|
644
640
|
console.error("Sum from loop:", glowSumProofLoop.toString());
|
|
645
641
|
console.error("Sum from reduce:", totalGlowWeight.toString());
|
|
@@ -647,10 +643,10 @@ export async function createWeeklyReport({
|
|
|
647
643
|
}
|
|
648
644
|
|
|
649
645
|
const usdgSumProofLoop = leavesWithProofs.reduce(
|
|
650
|
-
(acc, l) => acc
|
|
651
|
-
|
|
646
|
+
(acc, l) => acc + BigInt(l.usdgWeight),
|
|
647
|
+
0n
|
|
652
648
|
);
|
|
653
|
-
if (
|
|
649
|
+
if (usdgSumProofLoop !== totalUSDGWeight) {
|
|
654
650
|
console.error("USDG Weight Sum Mismatch (Post-73):");
|
|
655
651
|
console.error("Sum from loop:", usdgSumProofLoop.toString());
|
|
656
652
|
console.error("Sum from reduce:", totalUSDGWeight.toString());
|
|
@@ -665,10 +661,7 @@ export async function createWeeklyReport({
|
|
|
665
661
|
|
|
666
662
|
// Convert total USDG weight back to human-readable decimal for deviation check.
|
|
667
663
|
const totalUSDGWeightHuman = new Decimal(
|
|
668
|
-
formatUnits(
|
|
669
|
-
BigInt(totalUSDGWeight.toString()),
|
|
670
|
-
USDG_WEIGHT_DECIMAL_PRECISION
|
|
671
|
-
)
|
|
664
|
+
formatUnits(totalUSDGWeight, USDG_WEIGHT_DECIMAL_PRECISION)
|
|
672
665
|
);
|
|
673
666
|
// Check deviation between total adjusted credits used and the final sum of USDG weights.
|
|
674
667
|
if (
|
|
@@ -689,10 +682,7 @@ export async function createWeeklyReport({
|
|
|
689
682
|
|
|
690
683
|
// Convert total Glow weight back to human-readable decimal.
|
|
691
684
|
const totalGlowWeightHuman = new Decimal(
|
|
692
|
-
formatUnits(
|
|
693
|
-
BigInt(totalGlowWeight.toString()),
|
|
694
|
-
GLOW_WEIGHT_DECIMAL_PRECISION
|
|
695
|
-
)
|
|
685
|
+
formatUnits(totalGlowWeight, GLOW_WEIGHT_DECIMAL_PRECISION)
|
|
696
686
|
);
|
|
697
687
|
// Sum the original weekly protocol fee payments from farm data.
|
|
698
688
|
const totalProtocolFeePayments = farms.reduce(
|
|
@@ -723,7 +713,7 @@ export async function createWeeklyReport({
|
|
|
723
713
|
weekNumber: week,
|
|
724
714
|
totalCreditsProduced: formatUnits(totalCreditsProduced18dp, 18), // Original reported total
|
|
725
715
|
totalCreditsProducedBN: totalCreditsProduced18dp.toString(),
|
|
726
|
-
totalGlowWeightInFinalized: totalGlowWeight.toString(), // Total weight as
|
|
716
|
+
totalGlowWeightInFinalized: totalGlowWeight.toString(), // Total weight as bigint string
|
|
727
717
|
totalGlowWeightHuman: totalGlowWeightHuman.toString(), // Total weight as human-readable decimal
|
|
728
718
|
totalUSDGWeightInFinalized: totalUSDGWeight.toString(),
|
|
729
719
|
totalUSDGWeightHuman: totalUSDGWeightHuman.toString(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { solidityPackedKeccak256 } from "ethers";
|
|
2
2
|
const leafTypes = ["address", "uint256", "uint256"];
|
|
3
3
|
|
|
4
4
|
type HashLeafArgs = {
|
|
@@ -11,7 +11,7 @@ export function hashLeaf({
|
|
|
11
11
|
glowWeight,
|
|
12
12
|
usdcWeight,
|
|
13
13
|
}: HashLeafArgs): string {
|
|
14
|
-
const hash =
|
|
14
|
+
const hash = solidityPackedKeccak256(leafTypes, [
|
|
15
15
|
address,
|
|
16
16
|
glowWeight,
|
|
17
17
|
usdcWeight,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Contract, MaxUint256, type BigNumberish, type Signer } from "ethers";
|
|
2
2
|
import { FORWARDER_ABI } from "../abis/forwarderABI";
|
|
3
3
|
import { ERC20_ABI } from "../abis/erc20.abi";
|
|
4
4
|
import { getAddresses } from "../../constants/addresses";
|
|
@@ -26,7 +26,7 @@ export type Currency = "USDC" | "GLW" | "USDG";
|
|
|
26
26
|
|
|
27
27
|
// Forward parameters interface
|
|
28
28
|
export interface ForwardParams {
|
|
29
|
-
amount:
|
|
29
|
+
amount: bigint;
|
|
30
30
|
userAddress: string;
|
|
31
31
|
type: ForwardType;
|
|
32
32
|
currency?: Currency;
|
|
@@ -63,17 +63,14 @@ function parseEthersError(error: unknown): string {
|
|
|
63
63
|
|
|
64
64
|
// Type-guard style helper to ensure a signer exists throughout the rest of the function.
|
|
65
65
|
function assertSigner(
|
|
66
|
-
maybeSigner:
|
|
67
|
-
): asserts maybeSigner is
|
|
66
|
+
maybeSigner: Signer | undefined
|
|
67
|
+
): asserts maybeSigner is Signer {
|
|
68
68
|
if (!maybeSigner) {
|
|
69
69
|
throw new Error(ForwarderError.SIGNER_NOT_AVAILABLE);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
export function useForwarder(
|
|
74
|
-
signer: providers.JsonRpcSigner | undefined,
|
|
75
|
-
CHAIN_ID: number
|
|
76
|
-
) {
|
|
73
|
+
export function useForwarder(signer: Signer | undefined, CHAIN_ID: number) {
|
|
77
74
|
// Use dynamic addresses based on chain configuration
|
|
78
75
|
const ADDRESSES = getAddresses(CHAIN_ID);
|
|
79
76
|
|
|
@@ -171,7 +168,7 @@ export function useForwarder(
|
|
|
171
168
|
async function checkTokenAllowance(
|
|
172
169
|
owner: string,
|
|
173
170
|
currency: Currency = "USDC"
|
|
174
|
-
): Promise<
|
|
171
|
+
): Promise<bigint> {
|
|
175
172
|
assertSigner(signer);
|
|
176
173
|
|
|
177
174
|
try {
|
|
@@ -179,7 +176,7 @@ export function useForwarder(
|
|
|
179
176
|
if (!tokenContract)
|
|
180
177
|
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
|
181
178
|
|
|
182
|
-
const allowance:
|
|
179
|
+
const allowance: bigint = await tokenContract.allowance(
|
|
183
180
|
owner,
|
|
184
181
|
ADDRESSES.FORWARDER
|
|
185
182
|
);
|
|
@@ -197,7 +194,7 @@ export function useForwarder(
|
|
|
197
194
|
async function checkTokenBalance(
|
|
198
195
|
owner: string,
|
|
199
196
|
currency: Currency = "USDC"
|
|
200
|
-
): Promise<
|
|
197
|
+
): Promise<bigint> {
|
|
201
198
|
assertSigner(signer);
|
|
202
199
|
|
|
203
200
|
try {
|
|
@@ -205,7 +202,7 @@ export function useForwarder(
|
|
|
205
202
|
if (!tokenContract)
|
|
206
203
|
throw new Error(ForwarderError.CONTRACT_NOT_AVAILABLE);
|
|
207
204
|
|
|
208
|
-
const balance:
|
|
205
|
+
const balance: bigint = await tokenContract.balanceOf(owner);
|
|
209
206
|
return balance;
|
|
210
207
|
} catch (error) {
|
|
211
208
|
throw new Error(parseEthersError(error));
|
|
@@ -218,7 +215,7 @@ export function useForwarder(
|
|
|
218
215
|
* @param currency The currency to approve
|
|
219
216
|
*/
|
|
220
217
|
async function approveToken(
|
|
221
|
-
amount:
|
|
218
|
+
amount: BigNumberish,
|
|
222
219
|
currency: Currency = "USDC"
|
|
223
220
|
): Promise<boolean> {
|
|
224
221
|
assertSigner(signer);
|
|
@@ -276,16 +273,16 @@ export function useForwarder(
|
|
|
276
273
|
}
|
|
277
274
|
|
|
278
275
|
// Check allowance and approve if necessary
|
|
279
|
-
const allowance:
|
|
276
|
+
const allowance: bigint = await tokenContract.allowance(
|
|
280
277
|
owner,
|
|
281
278
|
ADDRESSES.FORWARDER
|
|
282
279
|
);
|
|
283
280
|
|
|
284
|
-
if (allowance
|
|
281
|
+
if (allowance < amount) {
|
|
285
282
|
try {
|
|
286
283
|
const approveTx = await tokenContract.approve(
|
|
287
284
|
ADDRESSES.FORWARDER,
|
|
288
|
-
|
|
285
|
+
MaxUint256
|
|
289
286
|
);
|
|
290
287
|
await approveTx.wait();
|
|
291
288
|
} catch (approveError) {
|
|
@@ -311,26 +308,26 @@ export function useForwarder(
|
|
|
311
308
|
throw new Error(`Unsupported currency for forwarding: ${currency}`);
|
|
312
309
|
}
|
|
313
310
|
|
|
314
|
-
// Run a static call first to surface any revert reason
|
|
311
|
+
// Run a static call first to surface any revert reason (ethers v6)
|
|
315
312
|
try {
|
|
316
|
-
// If PayAuditFees, call forward() even for USDC
|
|
317
313
|
if (!isAuditFees && currency === "USDC") {
|
|
318
|
-
await forwarderContract
|
|
319
|
-
|
|
320
|
-
ADDRESSES.FOUNDATION_WALLET,
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
);
|
|
314
|
+
await forwarderContract
|
|
315
|
+
.getFunction("swapUSDCAndForwardUSDG")
|
|
316
|
+
.staticCall(amount, ADDRESSES.FOUNDATION_WALLET, message, {
|
|
317
|
+
from: owner,
|
|
318
|
+
});
|
|
324
319
|
} else {
|
|
325
|
-
await forwarderContract
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
320
|
+
await forwarderContract
|
|
321
|
+
.getFunction("forward")
|
|
322
|
+
.staticCall(
|
|
323
|
+
tokenAddress,
|
|
324
|
+
isAuditFees
|
|
325
|
+
? ADDRESSES.AUDIT_FEE_WALLET
|
|
326
|
+
: ADDRESSES.FOUNDATION_WALLET,
|
|
327
|
+
amount,
|
|
328
|
+
message,
|
|
329
|
+
{ from: owner }
|
|
330
|
+
);
|
|
334
331
|
}
|
|
335
332
|
} catch (staticError) {
|
|
336
333
|
throw new Error(parseEthersError(staticError));
|
|
@@ -339,13 +336,13 @@ export function useForwarder(
|
|
|
339
336
|
// Execute the forward transaction
|
|
340
337
|
let tx;
|
|
341
338
|
if (!isAuditFees && currency === "USDC") {
|
|
342
|
-
tx = await forwarderContract.swapUSDCAndForwardUSDG(
|
|
339
|
+
tx = await forwarderContract.getFunction("swapUSDCAndForwardUSDG")(
|
|
343
340
|
amount,
|
|
344
341
|
ADDRESSES.FOUNDATION_WALLET,
|
|
345
342
|
message
|
|
346
343
|
);
|
|
347
344
|
} else {
|
|
348
|
-
tx = await forwarderContract.forward(
|
|
345
|
+
tx = await forwarderContract.getFunction("forward")(
|
|
349
346
|
tokenAddress,
|
|
350
347
|
isAuditFees
|
|
351
348
|
? ADDRESSES.AUDIT_FEE_WALLET
|
|
@@ -368,7 +365,7 @@ export function useForwarder(
|
|
|
368
365
|
* Forward tokens for protocol fee payment and GCTL minting with staking
|
|
369
366
|
*/
|
|
370
367
|
async function payProtocolFeeAndMintGCTLAndStake(
|
|
371
|
-
amount:
|
|
368
|
+
amount: bigint,
|
|
372
369
|
userAddress: string,
|
|
373
370
|
applicationId: string,
|
|
374
371
|
regionId?: number,
|
|
@@ -397,7 +394,7 @@ export function useForwarder(
|
|
|
397
394
|
* Forward tokens for protocol fee payment only
|
|
398
395
|
*/
|
|
399
396
|
async function payProtocolFee(
|
|
400
|
-
amount:
|
|
397
|
+
amount: bigint,
|
|
401
398
|
userAddress: string,
|
|
402
399
|
applicationId: string,
|
|
403
400
|
currency: Currency = "USDC"
|
|
@@ -417,7 +414,7 @@ export function useForwarder(
|
|
|
417
414
|
* Forward USDC to mint GCTL and stake to a region
|
|
418
415
|
*/
|
|
419
416
|
async function mintGCTLAndStake(
|
|
420
|
-
amount:
|
|
417
|
+
amount: bigint,
|
|
421
418
|
userAddress: string,
|
|
422
419
|
regionId?: number,
|
|
423
420
|
currency: Currency = "USDC"
|
|
@@ -444,7 +441,7 @@ export function useForwarder(
|
|
|
444
441
|
* Forward USDC to mint GCTL (existing functionality, keeping for compatibility)
|
|
445
442
|
*/
|
|
446
443
|
async function mintGCTL(
|
|
447
|
-
amount:
|
|
444
|
+
amount: bigint,
|
|
448
445
|
userAddress: string,
|
|
449
446
|
currency: Currency = "USDC"
|
|
450
447
|
): Promise<string> {
|
|
@@ -469,7 +466,7 @@ export function useForwarder(
|
|
|
469
466
|
* Forward tokens to pay audit fees (USDC only, calls forward())
|
|
470
467
|
*/
|
|
471
468
|
async function payAuditFees(
|
|
472
|
-
amount:
|
|
469
|
+
amount: bigint,
|
|
473
470
|
userAddress: string,
|
|
474
471
|
applicationId: string
|
|
475
472
|
): Promise<string> {
|
|
@@ -488,7 +485,7 @@ export function useForwarder(
|
|
|
488
485
|
* Forward tokens to buy a solar farm
|
|
489
486
|
*/
|
|
490
487
|
async function buySolarFarm(
|
|
491
|
-
amount:
|
|
488
|
+
amount: bigint,
|
|
492
489
|
userAddress: string,
|
|
493
490
|
farmId: string,
|
|
494
491
|
currency: Currency = "USDC"
|
|
@@ -547,27 +544,31 @@ export function useForwarder(
|
|
|
547
544
|
);
|
|
548
545
|
}
|
|
549
546
|
|
|
550
|
-
const
|
|
551
|
-
const
|
|
552
|
-
|
|
547
|
+
const feeData = await signer.provider?.getFeeData();
|
|
548
|
+
const gasPrice =
|
|
549
|
+
feeData?.gasPrice ?? feeData?.maxFeePerGas ?? (0n as bigint);
|
|
550
|
+
if (gasPrice === 0n) {
|
|
551
|
+
throw new Error("Could not fetch gas price to estimate cost.");
|
|
552
|
+
}
|
|
553
|
+
const estimatedGas: bigint =
|
|
553
554
|
!isAuditFees && currency === "USDC"
|
|
554
|
-
? await forwarderContract
|
|
555
|
-
|
|
556
|
-
ADDRESSES.FOUNDATION_WALLET,
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
const estimatedCost = estimatedGas
|
|
555
|
+
? await forwarderContract
|
|
556
|
+
.getFunction("swapUSDCAndForwardUSDG")
|
|
557
|
+
.estimateGas(amount, ADDRESSES.FOUNDATION_WALLET, message)
|
|
558
|
+
: await forwarderContract
|
|
559
|
+
.getFunction("forward")
|
|
560
|
+
.estimateGas(
|
|
561
|
+
tokenAddress,
|
|
562
|
+
isAuditFees
|
|
563
|
+
? ADDRESSES.AUDIT_FEE_WALLET
|
|
564
|
+
: ADDRESSES.FOUNDATION_WALLET,
|
|
565
|
+
amount,
|
|
566
|
+
message
|
|
567
|
+
);
|
|
568
|
+
const estimatedCost: bigint = estimatedGas * gasPrice;
|
|
568
569
|
|
|
569
570
|
if (ethPriceInUSD) {
|
|
570
|
-
const estimatedCostInEth = formatEther(estimatedCost
|
|
571
|
+
const estimatedCostInEth = formatEther(estimatedCost);
|
|
571
572
|
const estimatedCostInUSD = (
|
|
572
573
|
parseFloat(estimatedCostInEth) * ethPriceInUSD
|
|
573
574
|
).toFixed(2);
|
|
@@ -588,7 +589,7 @@ export function useForwarder(
|
|
|
588
589
|
* @param recipient Address to mint USDC to
|
|
589
590
|
*/
|
|
590
591
|
async function mintTestUSDC(
|
|
591
|
-
amount:
|
|
592
|
+
amount: bigint,
|
|
592
593
|
recipient: string
|
|
593
594
|
): Promise<string> {
|
|
594
595
|
assertSigner(signer);
|
package/src/lib/types/index.ts
CHANGED
|
@@ -152,6 +152,70 @@ export interface RegionMetadata {
|
|
|
152
152
|
flag?: string;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
// ----------------------------- Kickstarters ---------------------------------
|
|
156
|
+
export type KickstarterStatus =
|
|
157
|
+
| "draft"
|
|
158
|
+
| "awaiting-kickoff"
|
|
159
|
+
| "collecting-support"
|
|
160
|
+
| "ready-to-activate"
|
|
161
|
+
| "completed"
|
|
162
|
+
| "expired"
|
|
163
|
+
| "cancelled"
|
|
164
|
+
| "suspended";
|
|
165
|
+
|
|
166
|
+
export interface CreateKickstarterPayload {
|
|
167
|
+
creatorWallet: string;
|
|
168
|
+
regionName: string;
|
|
169
|
+
isUs?: boolean;
|
|
170
|
+
title: string;
|
|
171
|
+
description: string;
|
|
172
|
+
stakeTargetGctl: string; // decimal string
|
|
173
|
+
requiredFarmCount?: number; // defaults server-side
|
|
174
|
+
requiredInstallerCount?: number; // defaults server-side
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface KickstarterCreateResponse {
|
|
178
|
+
success: true;
|
|
179
|
+
id: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface Kickstarter {
|
|
183
|
+
id: string;
|
|
184
|
+
regionId: number;
|
|
185
|
+
creatorWallet: string;
|
|
186
|
+
title: string;
|
|
187
|
+
description: string;
|
|
188
|
+
slug: string;
|
|
189
|
+
status: KickstarterStatus | string;
|
|
190
|
+
createdAt: string; // ISO 8601
|
|
191
|
+
updatedAt: string; // ISO 8601
|
|
192
|
+
publishedAt?: string; // ISO 8601
|
|
193
|
+
completedAt?: string; // ISO 8601
|
|
194
|
+
cancelledAt?: string; // ISO 8601
|
|
195
|
+
expiredAt?: string; // ISO 8601
|
|
196
|
+
deadline: string; // ISO 8601
|
|
197
|
+
stakeTargetGctl: string; // decimal string
|
|
198
|
+
requiredFarmCount: number;
|
|
199
|
+
requiredInstallerCount: number;
|
|
200
|
+
stakeContributed: boolean;
|
|
201
|
+
farmProvided: boolean;
|
|
202
|
+
installerCertified: boolean;
|
|
203
|
+
kickoffTransferTxId?: string;
|
|
204
|
+
kickoffMintTxId?: string;
|
|
205
|
+
kickoffStakeEventId?: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface ActivationEvent {
|
|
209
|
+
id: string;
|
|
210
|
+
regionId: number;
|
|
211
|
+
epoch: number;
|
|
212
|
+
stakeThresholdMet: boolean;
|
|
213
|
+
solarFarmRequirementMet: boolean;
|
|
214
|
+
installerRequirementMet: boolean;
|
|
215
|
+
activated: boolean;
|
|
216
|
+
ts: string; // ISO 8601
|
|
217
|
+
}
|
|
218
|
+
|
|
155
219
|
// ---------------------------------------------------------------------------
|
|
156
220
|
// Barrel exports (convenience)
|
|
157
221
|
// ---------------------------------------------------------------------------
|
package/src/utils/hash-leaf.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { solidityPackedKeccak256 } from "ethers";
|
|
2
2
|
const leafTypes = ["address", "uint256", "uint256"];
|
|
3
3
|
|
|
4
4
|
type HashLeafArgs = {
|
|
@@ -11,7 +11,7 @@ export function hashLeaf({
|
|
|
11
11
|
glowWeight,
|
|
12
12
|
usdcWeight,
|
|
13
13
|
}: HashLeafArgs): string {
|
|
14
|
-
const hash =
|
|
14
|
+
const hash = solidityPackedKeccak256(leafTypes, [
|
|
15
15
|
address,
|
|
16
16
|
glowWeight,
|
|
17
17
|
usdcWeight,
|