@glowlabs-org/utils 0.2.47 → 0.2.48

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.
Files changed (36) hide show
  1. package/dist/cjs/browser.d.ts +1 -0
  2. package/dist/cjs/browser.js +12211 -4
  3. package/dist/cjs/browser.js.map +1 -1
  4. package/dist/cjs/index.d.ts +1 -0
  5. package/dist/cjs/index.js +95 -1
  6. package/dist/cjs/index.js.map +1 -1
  7. package/dist/cjs/lib/control-api/control-router.d.ts +3 -3
  8. package/dist/cjs/lib/control-api/kickstarter-router.d.ts +9 -0
  9. package/dist/cjs/lib/control-api/region-router.d.ts +1 -6
  10. package/dist/cjs/lib/types/index.d.ts +30 -0
  11. package/dist/cjs/{region-router-1QcGCT_a.js → region-router-ihtk6PPi.js} +7 -66
  12. package/dist/cjs/region-router-ihtk6PPi.js.map +1 -0
  13. package/dist/cjs/utils/stake-control.d.ts +156 -0
  14. package/dist/esm/browser.d.ts +1 -0
  15. package/dist/esm/browser.js +12196 -2
  16. package/dist/esm/browser.js.map +1 -1
  17. package/dist/esm/index.d.ts +1 -0
  18. package/dist/esm/index.js +96 -3
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/lib/control-api/control-router.d.ts +3 -3
  21. package/dist/esm/lib/control-api/kickstarter-router.d.ts +9 -0
  22. package/dist/esm/lib/control-api/region-router.d.ts +1 -6
  23. package/dist/esm/lib/types/index.d.ts +30 -0
  24. package/dist/esm/{region-router-DDMKweoS.js → region-router-BoyHO9Zp.js} +7 -66
  25. package/dist/esm/region-router-BoyHO9Zp.js.map +1 -0
  26. package/dist/esm/utils/stake-control.d.ts +156 -0
  27. package/package.json +6 -3
  28. package/src/browser.ts +1 -0
  29. package/src/index.ts +1 -0
  30. package/src/lib/control-api/control-router.ts +3 -10
  31. package/src/lib/control-api/kickstarter-router.ts +119 -0
  32. package/src/lib/control-api/region-router.ts +4 -75
  33. package/src/lib/types/index.ts +44 -6
  34. package/src/utils/stake-control.ts +343 -0
  35. package/dist/cjs/region-router-1QcGCT_a.js.map +0 -1
  36. package/dist/esm/region-router-DDMKweoS.js.map +0 -1
@@ -0,0 +1,156 @@
1
+ import z from "zod";
2
+ export declare const stakeControlEIP712Domain: {
3
+ readonly name: "ControlManager";
4
+ readonly version: "1";
5
+ readonly chainId: number;
6
+ readonly verifyingContract: "0x0000000000000000000000000000000000000000";
7
+ };
8
+ export declare const stakeEIP712Types: {
9
+ readonly Stake: readonly [{
10
+ readonly name: "nonce";
11
+ readonly type: "uint256";
12
+ }, {
13
+ readonly name: "amount";
14
+ readonly type: "uint256";
15
+ }, {
16
+ readonly name: "toZoneId";
17
+ readonly type: "uint256";
18
+ }, {
19
+ readonly name: "deadline";
20
+ readonly type: "uint256";
21
+ }];
22
+ };
23
+ export declare const unstakeUnlockEIP712Types: {
24
+ readonly Unstake: readonly [{
25
+ readonly name: "nonce";
26
+ readonly type: "uint256";
27
+ }, {
28
+ readonly name: "amount";
29
+ readonly type: "uint256";
30
+ }, {
31
+ readonly name: "fromZoneId";
32
+ readonly type: "uint256";
33
+ }, {
34
+ readonly name: "deadline";
35
+ readonly type: "uint256";
36
+ }];
37
+ };
38
+ export declare const unstakeMoveEIP712Types: {
39
+ readonly UnstakeMove: readonly [{
40
+ readonly name: "nonce";
41
+ readonly type: "uint256";
42
+ }, {
43
+ readonly name: "amount";
44
+ readonly type: "uint256";
45
+ }, {
46
+ readonly name: "fromZoneId";
47
+ readonly type: "uint256";
48
+ }, {
49
+ readonly name: "toZoneId";
50
+ readonly type: "uint256";
51
+ }, {
52
+ readonly name: "deadline";
53
+ readonly type: "uint256";
54
+ }];
55
+ };
56
+ export declare const restakeEIP712Types: {
57
+ readonly Restake: readonly [{
58
+ readonly name: "nonce";
59
+ readonly type: "uint256";
60
+ }, {
61
+ readonly name: "amount";
62
+ readonly type: "uint256";
63
+ }, {
64
+ readonly name: "fromZoneId";
65
+ readonly type: "uint256";
66
+ }, {
67
+ readonly name: "toZoneId";
68
+ readonly type: "uint256";
69
+ }, {
70
+ readonly name: "deadline";
71
+ readonly type: "uint256";
72
+ }];
73
+ };
74
+ export declare const stakeSignatureRequestSchema: z.ZodObject<{
75
+ wallet: z.ZodString;
76
+ signature: z.ZodString;
77
+ nonce: z.ZodString;
78
+ amount: z.ZodString;
79
+ toZoneId: z.ZodString;
80
+ deadline: z.ZodString;
81
+ }, z.core.$strip>;
82
+ export declare const unstakeUnlockSignatureRequestSchema: z.ZodObject<{
83
+ wallet: z.ZodString;
84
+ signature: z.ZodString;
85
+ nonce: z.ZodString;
86
+ amount: z.ZodString;
87
+ fromZoneId: z.ZodString;
88
+ deadline: z.ZodString;
89
+ }, z.core.$strip>;
90
+ export declare const unstakeMoveSignatureRequestSchema: z.ZodObject<{
91
+ wallet: z.ZodString;
92
+ signature: z.ZodString;
93
+ nonce: z.ZodString;
94
+ amount: z.ZodString;
95
+ fromZoneId: z.ZodString;
96
+ toZoneId: z.ZodString;
97
+ deadline: z.ZodString;
98
+ }, z.core.$strip>;
99
+ export declare const restakeSignatureRequestSchema: z.ZodObject<{
100
+ wallet: z.ZodString;
101
+ signature: z.ZodString;
102
+ nonce: z.ZodString;
103
+ amount: z.ZodString;
104
+ fromZoneId: z.ZodString;
105
+ toZoneId: z.ZodString;
106
+ deadline: z.ZodString;
107
+ }, z.core.$strip>;
108
+ export type StakeSignatureRequest = z.infer<typeof stakeSignatureRequestSchema>;
109
+ export type UnstakeUnlockSignatureRequest = z.infer<typeof unstakeUnlockSignatureRequestSchema>;
110
+ export type UnstakeMoveSignatureRequest = z.infer<typeof unstakeMoveSignatureRequestSchema>;
111
+ export type RestakeSignatureRequest = z.infer<typeof restakeSignatureRequestSchema>;
112
+ export type StakeMessage = {
113
+ nonce: bigint;
114
+ amount: bigint;
115
+ toZoneId: bigint;
116
+ deadline: bigint;
117
+ };
118
+ export type UnstakeUnlockMessage = {
119
+ nonce: bigint;
120
+ amount: bigint;
121
+ fromZoneId: bigint;
122
+ deadline: bigint;
123
+ };
124
+ export type UnstakeMoveMessage = {
125
+ nonce: bigint;
126
+ amount: bigint;
127
+ fromZoneId: bigint;
128
+ toZoneId: bigint;
129
+ deadline: bigint;
130
+ };
131
+ export type RestakeMessage = {
132
+ nonce: bigint;
133
+ amount: bigint;
134
+ fromZoneId: bigint;
135
+ toZoneId: bigint;
136
+ deadline: bigint;
137
+ };
138
+ export type SignatureValidationReason = "deadline_expired" | "signature_failed" | "signer_mismatch" | null;
139
+ export type SignatureValidationResult = {
140
+ valid: boolean;
141
+ recovered: string | null;
142
+ reason: SignatureValidationReason;
143
+ };
144
+ type StakeMessageInput = Pick<StakeSignatureRequest, "nonce" | "amount" | "toZoneId" | "deadline">;
145
+ type UnstakeUnlockMessageInput = Pick<UnstakeUnlockSignatureRequest, "nonce" | "amount" | "fromZoneId" | "deadline">;
146
+ type UnstakeMoveMessageInput = Pick<UnstakeMoveSignatureRequest, "nonce" | "amount" | "fromZoneId" | "toZoneId" | "deadline">;
147
+ type RestakeMessageInput = Pick<RestakeSignatureRequest, "nonce" | "amount" | "fromZoneId" | "toZoneId" | "deadline">;
148
+ export declare function buildStakeMessage(req: StakeMessageInput): StakeMessage;
149
+ export declare function buildUnstakeUnlockMessage(req: UnstakeUnlockMessageInput): UnstakeUnlockMessage;
150
+ export declare function buildUnstakeMoveMessage(req: UnstakeMoveMessageInput): UnstakeMoveMessage;
151
+ export declare function buildRestakeMessage(req: RestakeMessageInput): RestakeMessage;
152
+ export declare function validateStakeSignature(input: StakeSignatureRequest, domain?: typeof stakeControlEIP712Domain): Promise<SignatureValidationResult>;
153
+ export declare function validateUnstakeUnlockSignature(input: UnstakeUnlockSignatureRequest, domain?: typeof stakeControlEIP712Domain): Promise<SignatureValidationResult>;
154
+ export declare function validateUnstakeMoveSignature(input: UnstakeMoveSignatureRequest, domain?: typeof stakeControlEIP712Domain): Promise<SignatureValidationResult>;
155
+ export declare function validateRestakeSignature(input: RestakeSignatureRequest, domain?: typeof stakeControlEIP712Domain): Promise<SignatureValidationResult>;
156
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glowlabs-org/utils",
3
- "version": "0.2.47",
3
+ "version": "0.2.48",
4
4
  "description": "A library containing all typechain types and addresses relating to the glow guarded launch",
5
5
  "keywords": [],
6
6
  "author": "",
@@ -41,10 +41,10 @@
41
41
  "node": ">=16"
42
42
  },
43
43
  "peerDependencies": {
44
+ "decimal.js": "^10.4.3",
44
45
  "ethers": "6.x.x",
45
46
  "merkletreejs": "^0.3.11",
46
- "viem": "^2.19.7",
47
- "decimal.js": "^10.4.3"
47
+ "viem": "^2.19.7"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@rollup/plugin-commonjs": "^26.0.1",
@@ -61,6 +61,9 @@
61
61
  "typescript": "^5.5.4",
62
62
  "viem": "^2.7.16"
63
63
  },
64
+ "dependencies": {
65
+ "zod": "^4.0.17"
66
+ },
64
67
  "scripts": {
65
68
  "test": "echo \"Error: no test specified\" && exit 1",
66
69
  "build": "rollup -c",
package/src/browser.ts CHANGED
@@ -7,3 +7,4 @@ export * from "./lib/abis/forwarderABI";
7
7
  export * from "./constants/addresses";
8
8
  export * from "./constants/weights";
9
9
  export * from "./constants/urls";
10
+ export * from "./utils/stake-control";
package/src/index.ts CHANGED
@@ -9,3 +9,4 @@ export {
9
9
  export { useForwarder } from "./lib/hooks/use-forwarder";
10
10
  export { ControlRouter } from "./lib/control-api/control-router";
11
11
  export { RegionRouter } from "./lib/control-api/region-router";
12
+ export { KickstarterRouter } from "./lib/control-api/kickstarter-router";
@@ -114,6 +114,7 @@ export function ControlRouter(baseUrl: string) {
114
114
  const data = await request<{ transfers: PendingTransfer[] }>(
115
115
  `/transfers/pending${buildPaginationQuery(page, limit)}`
116
116
  );
117
+
117
118
  return data.transfers ?? [];
118
119
  } catch (error) {
119
120
  throw new Error(parseApiError(error));
@@ -192,14 +193,9 @@ export function ControlRouter(baseUrl: string) {
192
193
  let isUnstaking = false;
193
194
  let isRetryingFailedOperation = false;
194
195
 
195
- const stakeGctl = async (
196
- wallet: string,
197
- regionId: number,
198
- amount: string
199
- ): Promise<boolean> => {
196
+ const stakeGctl = async (stakeRequest: StakeRequest): Promise<boolean> => {
200
197
  isStaking = true;
201
198
  try {
202
- const stakeRequest: StakeRequest = { wallet, regionId, amount };
203
199
  await request(`/stake`, {
204
200
  method: "POST",
205
201
  headers: { "Content-Type": "application/json" },
@@ -214,13 +210,10 @@ export function ControlRouter(baseUrl: string) {
214
210
  };
215
211
 
216
212
  const unstakeGctl = async (
217
- wallet: string,
218
- regionId: number,
219
- amount: string
213
+ unstakeRequest: StakeRequest
220
214
  ): Promise<boolean> => {
221
215
  isUnstaking = true;
222
216
  try {
223
- const unstakeRequest: StakeRequest = { wallet, regionId, amount };
224
217
  await request(`/unstake`, {
225
218
  method: "POST",
226
219
  headers: { "Content-Type": "application/json" },
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+
3
+ import { regionMetadata } from "../region-metadata";
4
+ import type {
5
+ Kickstarter,
6
+ CreateKickstarterPayload,
7
+ KickstarterCreateResponse,
8
+ CommitKickstarterPayload,
9
+ CommitKickstarterResponse,
10
+ } from "../types";
11
+
12
+ function parseApiError(error: unknown): string {
13
+ if (!error) return "Unknown error";
14
+ if (error instanceof Error) return error.message;
15
+ const possible: any = error;
16
+ return possible?.error?.message ?? possible?.message ?? "Unknown error";
17
+ }
18
+
19
+ export function KickstarterRouter(baseUrl: string) {
20
+ if (!baseUrl) throw new Error("CONTROL API base URL is not set");
21
+
22
+ const request = async <T>(path: string, init?: RequestInit): Promise<T> => {
23
+ const res = await fetch(`${baseUrl}${path}`, init);
24
+ if (!res.ok) {
25
+ const errData = await res.json().catch(() => ({}));
26
+ throw new Error(errData?.error || `Request to ${path} failed`);
27
+ }
28
+ return (await res.json()) as T;
29
+ };
30
+
31
+ let isCreatingKickstarter = false;
32
+
33
+ const fetchKickstarters = async (): Promise<Kickstarter[]> => {
34
+ try {
35
+ const data = await request<{ kickstarters: Kickstarter[] }>(
36
+ `/kickstarters`
37
+ );
38
+ return data.kickstarters ?? [];
39
+ } catch (error) {
40
+ throw new Error(parseApiError(error));
41
+ }
42
+ };
43
+
44
+ const createKickstarter = async (
45
+ payload: CreateKickstarterPayload
46
+ ): Promise<KickstarterCreateResponse> => {
47
+ isCreatingKickstarter = true;
48
+ try {
49
+ const exists = Boolean(regionMetadata[payload.code]);
50
+ if (!exists) {
51
+ throw new Error(`Unknown region code: ${payload.code}`);
52
+ }
53
+ const data = await request<KickstarterCreateResponse>(`/kickstarters`, {
54
+ method: "POST",
55
+ headers: { "Content-Type": "application/json" },
56
+ body: JSON.stringify(payload),
57
+ });
58
+ return data;
59
+ } catch (error) {
60
+ throw new Error(parseApiError(error));
61
+ } finally {
62
+ isCreatingKickstarter = false;
63
+ }
64
+ };
65
+
66
+ const fetchKickstarter = async (idOrSlug: string): Promise<Kickstarter> => {
67
+ try {
68
+ const data = await request<{ kickstarter: Kickstarter }>(
69
+ `/kickstarters/${encodeURIComponent(idOrSlug)}`
70
+ );
71
+ return data.kickstarter;
72
+ } catch (error) {
73
+ throw new Error(parseApiError(error));
74
+ }
75
+ };
76
+
77
+ const fetchKickstartersByWallet = async (
78
+ wallet: string
79
+ ): Promise<Kickstarter[]> => {
80
+ try {
81
+ const data = await request<{ kickstarters: Kickstarter[] }>(
82
+ `/kickstarters/by-wallet/${encodeURIComponent(wallet)}`
83
+ );
84
+ return data.kickstarters ?? [];
85
+ } catch (error) {
86
+ throw new Error(parseApiError(error));
87
+ }
88
+ };
89
+
90
+ const commitKickstarter = async (
91
+ kickstarterId: string,
92
+ payload: CommitKickstarterPayload
93
+ ): Promise<CommitKickstarterResponse> => {
94
+ try {
95
+ const data = await request<CommitKickstarterResponse>(
96
+ `/kickstarters/commit/${encodeURIComponent(kickstarterId)}`,
97
+ {
98
+ method: "POST",
99
+ headers: { "Content-Type": "application/json" },
100
+ body: JSON.stringify(payload),
101
+ }
102
+ );
103
+ return data;
104
+ } catch (error) {
105
+ throw new Error(parseApiError(error));
106
+ }
107
+ };
108
+
109
+ return {
110
+ fetchKickstarters,
111
+ fetchKickstarter,
112
+ fetchKickstartersByWallet,
113
+ commitKickstarter,
114
+ createKickstarter,
115
+ get isCreatingKickstarter() {
116
+ return isCreatingKickstarter;
117
+ },
118
+ } as const;
119
+ }
@@ -6,10 +6,7 @@ import type {
6
6
  RegionWithMetadata,
7
7
  ActivationConfig,
8
8
  CreateRegionPayload,
9
- CreateKickstarterPayload,
10
- Kickstarter,
11
9
  ActivationEvent,
12
- KickstarterCreateResponse,
13
10
  RegionVcr,
14
11
  SponsoredFarm,
15
12
  } from "../types";
@@ -47,7 +44,6 @@ export function RegionRouter(baseUrl: string) {
47
44
  let cachedRegions: RegionWithMetadata[] = [];
48
45
  let isLoading = false;
49
46
  let isCreatingRegion = false;
50
- let isCreatingKickstarter = false;
51
47
 
52
48
  // -------------------------------------------------------------------------
53
49
  // Queries
@@ -112,17 +108,6 @@ export function RegionRouter(baseUrl: string) {
112
108
  }
113
109
  };
114
110
 
115
- const fetchKickstarters = async (): Promise<Kickstarter[]> => {
116
- try {
117
- const data = await request<{ kickstarters: Kickstarter[] }>(
118
- `/regions/kickstarters`
119
- );
120
- return data.kickstarters ?? [];
121
- } catch (error) {
122
- throw new Error(parseApiError(error));
123
- }
124
- };
125
-
126
111
  const fetchRegionSolarFarms = async (
127
112
  regionId: number
128
113
  ): Promise<SponsoredFarm[]> => {
@@ -156,56 +141,7 @@ export function RegionRouter(baseUrl: string) {
156
141
  }
157
142
  };
158
143
 
159
- const createKickstarter = async (
160
- payload: CreateKickstarterPayload
161
- ): Promise<KickstarterCreateResponse> => {
162
- isCreatingKickstarter = true;
163
- try {
164
- const exists = Boolean(regionMetadata[payload.code]);
165
- if (!exists) {
166
- throw new Error(`Unknown region code: ${payload.code}`);
167
- }
168
- const data = await request<KickstarterCreateResponse>(
169
- `/regions/kickstarters`,
170
- {
171
- method: "POST",
172
- headers: { "Content-Type": "application/json" },
173
- body: JSON.stringify(payload),
174
- }
175
- );
176
- // A new region may have been created; refresh regions cache
177
- await fetchRegions();
178
- return data;
179
- } catch (error) {
180
- throw new Error(parseApiError(error));
181
- } finally {
182
- isCreatingKickstarter = false;
183
- }
184
- };
185
-
186
- const fetchKickstarter = async (idOrSlug: string): Promise<Kickstarter> => {
187
- try {
188
- const data = await request<{ kickstarter: Kickstarter }>(
189
- `/regions/kickstarters/${encodeURIComponent(idOrSlug)}`
190
- );
191
- return data.kickstarter;
192
- } catch (error) {
193
- throw new Error(parseApiError(error));
194
- }
195
- };
196
-
197
- const fetchKickstartersByWallet = async (
198
- wallet: string
199
- ): Promise<Kickstarter[]> => {
200
- try {
201
- const data = await request<{ kickstarters: Kickstarter[] }>(
202
- `/regions/kickstarters/by-wallet/${encodeURIComponent(wallet)}`
203
- );
204
- return data.kickstarters ?? [];
205
- } catch (error) {
206
- throw new Error(parseApiError(error));
207
- }
208
- };
144
+ // Kickstarter-related logic moved to kickstarter-router.ts
209
145
 
210
146
  // -------------------------------------------------------------------------
211
147
  // Helpers (derived)
@@ -239,10 +175,10 @@ export function RegionRouter(baseUrl: string) {
239
175
  isUs: metadata.isUs,
240
176
  isActive: false,
241
177
  stake: "0",
242
- stakeThreshold: metadata.isUs ? "20000000000" : "2000000000000",
178
+ stakeThreshold: metadata.isUs ? "20000000000" : "200000000000",
243
179
  solarPanelsQuantity: 0,
244
- solarFarmThreshold: 0,
245
- installerThreshold: 0,
180
+ solarFarmThreshold: 10,
181
+ installerThreshold: 1,
246
182
  stakeProgress: 0,
247
183
  solarFarmCount: 0,
248
184
  solarFarmProgress: 0,
@@ -260,13 +196,9 @@ export function RegionRouter(baseUrl: string) {
260
196
  fetchActivationConfig,
261
197
  fetchActivationEvents,
262
198
  fetchRegionByIdOrSlug,
263
- fetchKickstarters,
264
- fetchKickstarter,
265
- fetchKickstartersByWallet,
266
199
  fetchRegionSolarFarms,
267
200
  getRegionByCode,
268
201
  createRegion,
269
- createKickstarter,
270
202
 
271
203
  // Cached data & flags
272
204
  get regions() {
@@ -278,8 +210,5 @@ export function RegionRouter(baseUrl: string) {
278
210
  get isCreatingRegion() {
279
211
  return isCreatingRegion;
280
212
  },
281
- get isCreatingKickstarter() {
282
- return isCreatingKickstarter;
283
- },
284
213
  } as const;
285
214
  }
@@ -34,6 +34,7 @@ export interface PendingTransfer {
34
34
  applicationId?: string;
35
35
  farmId?: string;
36
36
  regionId?: number;
37
+ kickstarterId?: string;
37
38
  }
38
39
 
39
40
  export interface TransferDetails extends PendingTransfer {
@@ -79,6 +80,9 @@ export interface StakeRequest {
79
80
  wallet: string;
80
81
  regionId: number;
81
82
  amount: string; // Amount in atomic units (10^6 = 1 GCTL)
83
+ signature: string; // 0x-prefixed 65-byte hex signature
84
+ deadline: string; // unix timestamp (as string)
85
+ nonce: string; // stringified integer
82
86
  }
83
87
 
84
88
  export interface RegionStake {
@@ -114,14 +118,14 @@ export interface RegionWithMetadata extends Region {
114
118
  isActive: boolean;
115
119
  stake: string; // current GCTL stake (atomic units)
116
120
  stakeThreshold: string; // threshold required to activate
117
- stakeProgress: number; // 0–1
121
+ stakeProgress: number; // stake / stakeThreshold (may exceed 1)
118
122
  solarFarmCount: number;
119
123
  solarPanelsQuantity: number;
120
- solarFarmThreshold: number; // always 3
121
- solarFarmProgress: number; // 0–1
124
+ solarFarmThreshold: number; // current minimum required (from constants)
125
+ solarFarmProgress: number; // solarFarmCount / solarFarmThreshold (may exceed 1)
122
126
  installerCount: number;
123
- installerThreshold: number; // always 1
124
- installerProgress: number; // 0 or 1
127
+ installerThreshold: number; // current minimum required (from constants)
128
+ installerProgress: number; // installerCount / installerThreshold (may exceed 1)
125
129
  }
126
130
 
127
131
  export interface ActivationConfig {
@@ -186,7 +190,7 @@ export interface Kickstarter {
186
190
  cancelledAt?: string; // ISO 8601
187
191
  expiredAt?: string; // ISO 8601
188
192
  deadline: string; // ISO 8601
189
- stakeTargetGctl: string; // decimal string
193
+ stakeTargetGctl: string; // atomic units (GCTL scaled by 10^6)
190
194
  requiredFarmCount: number;
191
195
  requiredInstallerCount: number;
192
196
  stakeContributed: boolean;
@@ -197,6 +201,19 @@ export interface Kickstarter {
197
201
  kickoffStakeEventId?: string;
198
202
  }
199
203
 
204
+ export interface CommitKickstarterPayload {
205
+ wallet: string; // 0x-prefixed 40-char hex
206
+ amount: string; // atomic GCTL, must equal stakeTargetGctl/KICKSTARTER_STAKE_PERCENTAGE
207
+ nonce: string; // uint256 as string
208
+ deadline: string; // unix seconds as string
209
+ signature: string; // 0x-prefixed 65-byte hex
210
+ }
211
+
212
+ export interface CommitKickstarterResponse {
213
+ success: true;
214
+ regionId: number;
215
+ }
216
+
200
217
  export interface ActivationEvent {
201
218
  id: string;
202
219
  regionId: number;
@@ -249,6 +266,27 @@ export interface RegionVcr {
249
266
  carbonCreditsPerWeek: number;
250
267
  }
251
268
 
269
+ // ----------------------------- API Responses --------------------------------
270
+ export interface RegionsResponse {
271
+ regions: RegionWithMetadata[];
272
+ }
273
+
274
+ export interface RegionResponse {
275
+ region: RegionVcr;
276
+ }
277
+
278
+ export interface ActivationEventsResponse {
279
+ events: ActivationEvent[];
280
+ }
281
+
282
+ export interface RegionSolarFarmsResponse {
283
+ sponsoredFarms: SponsoredFarm[];
284
+ }
285
+
286
+ export interface FetchRegionsParams {
287
+ isActive?: boolean;
288
+ }
289
+
252
290
  // ---------------------------------------------------------------------------
253
291
  // Barrel exports (convenience)
254
292
  // ---------------------------------------------------------------------------