genlayer-js 0.18.10 → 0.18.12

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 (76) hide show
  1. package/dist/chains/index.cjs +2 -2
  2. package/dist/chains/index.js +1 -1
  3. package/dist/{chunk-PPBY3UXF.cjs → chunk-5TKVNHAO.cjs} +1118 -305
  4. package/dist/{chunk-WZNF2WK4.js → chunk-NOFMB7RP.js} +1118 -305
  5. package/dist/{index-D9ONjYgl.d.cts → index-DsN7LGHA.d.cts} +1615 -459
  6. package/dist/{index-ZDqJWXj0.d.ts → index-sw3NAvBf.d.ts} +1615 -459
  7. package/dist/index.cjs +58 -58
  8. package/dist/index.d.cts +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +28 -28
  11. package/dist/types/index.d.cts +1 -1
  12. package/dist/types/index.d.ts +1 -1
  13. package/package.json +11 -1
  14. package/.eslintignore +0 -2
  15. package/.eslintrc.cjs +0 -59
  16. package/.github/pull_request_template.md +0 -43
  17. package/.github/workflows/publish.yml +0 -41
  18. package/.github/workflows/test.yml +0 -33
  19. package/.prettierignore +0 -19
  20. package/.prettierrc +0 -12
  21. package/.release-it.json +0 -64
  22. package/CHANGELOG.md +0 -304
  23. package/CLAUDE.md +0 -66
  24. package/CONTRIBUTING.md +0 -87
  25. package/renovate.json +0 -20
  26. package/src/abi/calldata/consts.ts +0 -14
  27. package/src/abi/calldata/decoder.ts +0 -86
  28. package/src/abi/calldata/encoder.ts +0 -178
  29. package/src/abi/calldata/index.ts +0 -3
  30. package/src/abi/calldata/string.ts +0 -83
  31. package/src/abi/index.ts +0 -6
  32. package/src/abi/staking.ts +0 -687
  33. package/src/abi/transactions.ts +0 -11
  34. package/src/accounts/IAccountActions.ts +0 -5
  35. package/src/accounts/account.ts +0 -9
  36. package/src/accounts/actions.ts +0 -34
  37. package/src/chains/actions.ts +0 -40
  38. package/src/chains/index.ts +0 -4
  39. package/src/chains/localnet.ts +0 -4016
  40. package/src/chains/studionet.ts +0 -4017
  41. package/src/chains/testnetAsimov.ts +0 -4013
  42. package/src/client/client.ts +0 -139
  43. package/src/config/snapID.ts +0 -4
  44. package/src/config/transactions.ts +0 -9
  45. package/src/contracts/actions.ts +0 -387
  46. package/src/global.d.ts +0 -9
  47. package/src/index.ts +0 -12
  48. package/src/staking/actions.ts +0 -691
  49. package/src/staking/index.ts +0 -2
  50. package/src/staking/utils.ts +0 -22
  51. package/src/transactions/ITransactionActions.ts +0 -15
  52. package/src/transactions/actions.ts +0 -113
  53. package/src/transactions/decoders.ts +0 -275
  54. package/src/types/accounts.ts +0 -1
  55. package/src/types/calldata.ts +0 -31
  56. package/src/types/chains.ts +0 -22
  57. package/src/types/clients.ts +0 -106
  58. package/src/types/contracts.ts +0 -32
  59. package/src/types/index.ts +0 -9
  60. package/src/types/metamaskClientResult.ts +0 -5
  61. package/src/types/network.ts +0 -1
  62. package/src/types/snapSource.ts +0 -1
  63. package/src/types/staking.ts +0 -225
  64. package/src/types/transactions.ts +0 -312
  65. package/src/utils/async.ts +0 -3
  66. package/src/utils/jsonifier.ts +0 -119
  67. package/src/wallet/actions.ts +0 -10
  68. package/src/wallet/connect.ts +0 -67
  69. package/src/wallet/metamaskClient.ts +0 -50
  70. package/tests/client.test-d.ts +0 -67
  71. package/tests/client.test.ts +0 -197
  72. package/tests/smoke.test.ts +0 -59
  73. package/tests/transactions.test.ts +0 -142
  74. package/tsconfig.json +0 -119
  75. package/tsconfig.vitest-temp.json +0 -41
  76. package/vitest.config.ts +0 -18
@@ -1,691 +0,0 @@
1
- import {getContract, decodeEventLog, PublicClient, Client, Transport, Chain, Account, Address as ViemAddress, GetContractReturnType, toHex, encodeFunctionData, BaseError, ContractFunctionRevertedError, decodeErrorResult, RawContractError} from "viem";
2
- import {GenLayerClient, GenLayerChain, Address} from "@/types";
3
- import {STAKING_ABI, VALIDATOR_WALLET_ABI} from "@/abi/staking";
4
- import {parseStakingAmount, formatStakingAmount} from "./utils";
5
- import {
6
- ValidatorInfo,
7
- ValidatorIdentity,
8
- BannedValidatorInfo,
9
- StakeInfo,
10
- EpochInfo,
11
- EpochData,
12
- StakingTransactionResult,
13
- ValidatorJoinResult,
14
- DelegatorJoinResult,
15
- ValidatorJoinOptions,
16
- ValidatorDepositOptions,
17
- ValidatorExitOptions,
18
- ValidatorClaimOptions,
19
- ValidatorPrimeOptions,
20
- SetOperatorOptions,
21
- SetIdentityOptions,
22
- DelegatorJoinOptions,
23
- DelegatorExitOptions,
24
- DelegatorClaimOptions,
25
- StakingContract,
26
- PendingDeposit,
27
- PendingWithdrawal,
28
- } from "@/types/staking";
29
-
30
- type ReadOnlyStakingContract = GetContractReturnType<typeof STAKING_ABI, PublicClient, ViemAddress>;
31
- type WalletClientWithAccount = Client<Transport, Chain, Account>;
32
-
33
- const FALLBACK_GAS = 1000000n;
34
- const GAS_BUFFER_MULTIPLIER = 2n;
35
-
36
- // Combined ABI for error decoding (both staking and validator wallet errors)
37
- const COMBINED_ERROR_ABI = [...STAKING_ABI, ...VALIDATOR_WALLET_ABI];
38
-
39
- function extractRevertReason(err: unknown): string {
40
- if (err instanceof BaseError) {
41
- // Try to find raw error data and decode it with our ABI
42
- const rawError = err.walk((e) => e instanceof RawContractError);
43
- if (rawError instanceof RawContractError && rawError.data && typeof rawError.data === "string") {
44
- try {
45
- const decoded = decodeErrorResult({
46
- abi: COMBINED_ERROR_ABI,
47
- data: rawError.data as `0x${string}`,
48
- });
49
- return decoded.errorName;
50
- } catch {
51
- // Fall through to other methods
52
- }
53
- }
54
-
55
- // Try to extract error data from the cause chain
56
- let current: unknown = err;
57
- while (current) {
58
- if (current && typeof current === "object") {
59
- const obj = current as Record<string, unknown>;
60
- // Check for data property that looks like hex error data
61
- if (obj.data && typeof obj.data === "string" && obj.data.startsWith("0x")) {
62
- try {
63
- const decoded = decodeErrorResult({
64
- abi: COMBINED_ERROR_ABI,
65
- data: obj.data as `0x${string}`,
66
- });
67
- return decoded.errorName;
68
- } catch {
69
- // Continue searching
70
- }
71
- }
72
- current = obj.cause;
73
- } else {
74
- break;
75
- }
76
- }
77
-
78
- const revertError = err.walk((e) => e instanceof ContractFunctionRevertedError);
79
- if (revertError instanceof ContractFunctionRevertedError) {
80
- // If viem already decoded it, use that
81
- if (revertError.data?.errorName) {
82
- return revertError.data.errorName;
83
- }
84
- return revertError.reason || "Unknown reason";
85
- }
86
- if (err.shortMessage) return err.shortMessage;
87
- }
88
- if (err instanceof Error) return err.message;
89
- return "Unknown reason";
90
- }
91
-
92
- export const stakingActions = (
93
- client: GenLayerClient<GenLayerChain>,
94
- publicClient: PublicClient,
95
- ) => {
96
- const executeWrite = async (options: {
97
- to: ViemAddress;
98
- data: `0x${string}`;
99
- value?: bigint;
100
- gas?: bigint;
101
- }): Promise<StakingTransactionResult> => {
102
- if (!client.account) {
103
- throw new Error("Account is required for write operations. Initialize client with a wallet account.");
104
- }
105
- const account = client.account;
106
-
107
- try {
108
- await publicClient.call({
109
- account,
110
- to: options.to,
111
- data: options.data,
112
- value: options.value,
113
- });
114
- } catch (err: unknown) {
115
- const revertReason = extractRevertReason(err);
116
- throw new Error(`Transaction would revert: ${revertReason}`);
117
- }
118
-
119
- let gasLimit = options.gas;
120
- if (!gasLimit) {
121
- try {
122
- const estimated = await publicClient.estimateGas({
123
- account,
124
- to: options.to,
125
- data: options.data,
126
- value: options.value,
127
- });
128
- gasLimit = estimated * GAS_BUFFER_MULTIPLIER;
129
- } catch {
130
- gasLimit = FALLBACK_GAS;
131
- }
132
- }
133
-
134
- const nonce = await publicClient.getTransactionCount({address: account.address as ViemAddress});
135
-
136
- const txRequest = await publicClient.prepareTransactionRequest({
137
- account,
138
- to: options.to,
139
- data: options.data,
140
- value: options.value,
141
- type: "legacy",
142
- nonce,
143
- gas: gasLimit,
144
- chain: client.chain,
145
- });
146
-
147
- const signTransaction = account.signTransaction;
148
- if (!signTransaction) {
149
- throw new Error("Account does not support signing transactions");
150
- }
151
- const serializedTx = await signTransaction(txRequest as Parameters<typeof signTransaction>[0]);
152
- const hash = await publicClient.sendRawTransaction({serializedTransaction: serializedTx});
153
- const receipt = await publicClient.waitForTransactionReceipt({hash});
154
-
155
- if (receipt.status === "reverted") {
156
- let revertReason = "Unknown reason";
157
- try {
158
- await publicClient.call({
159
- account,
160
- to: options.to,
161
- data: options.data,
162
- value: options.value,
163
- blockNumber: receipt.blockNumber,
164
- });
165
- const gasUsed = receipt.gasUsed;
166
- if (gasUsed >= gasLimit - 1000n) {
167
- revertReason = `Out of gas (used ${gasUsed}, limit ${gasLimit})`;
168
- } else {
169
- revertReason = `Unknown (simulation passes but tx reverts). Gas: ${gasUsed}/${gasLimit}`;
170
- }
171
- } catch (err: unknown) {
172
- revertReason = extractRevertReason(err);
173
- }
174
- throw new Error(`Transaction reverted: ${revertReason} (tx: ${hash})`);
175
- }
176
-
177
- return {
178
- transactionHash: receipt.transactionHash,
179
- blockNumber: receipt.blockNumber,
180
- gasUsed: receipt.gasUsed,
181
- };
182
- };
183
-
184
- const getStakingAddress = (): ViemAddress => {
185
- const stakingConfig = client.chain.stakingContract;
186
- if (!stakingConfig?.address || stakingConfig.address === "0x0000000000000000000000000000000000000000") {
187
- throw new Error("Staking is not supported on studio-based networks. Use testnet-asimov for staking operations.");
188
- }
189
- return stakingConfig.address as ViemAddress;
190
- };
191
-
192
- const getStakingContract = (): StakingContract => {
193
- const address = getStakingAddress();
194
- return getContract({
195
- address,
196
- abi: STAKING_ABI,
197
- client: {public: publicClient, wallet: client as unknown as WalletClientWithAccount},
198
- });
199
- };
200
-
201
- const getReadOnlyStakingContract = (): ReadOnlyStakingContract => {
202
- const address = getStakingAddress();
203
- return getContract({
204
- address,
205
- abi: STAKING_ABI,
206
- client: publicClient,
207
- });
208
- };
209
-
210
- return {
211
- validatorJoin: async (options: ValidatorJoinOptions): Promise<ValidatorJoinResult> => {
212
- const amount = parseStakingAmount(options.amount);
213
- const stakingAddress = getStakingAddress();
214
-
215
- const data = options.operator
216
- ? encodeFunctionData({
217
- abi: STAKING_ABI,
218
- functionName: "validatorJoin",
219
- args: [options.operator as ViemAddress],
220
- })
221
- : encodeFunctionData({
222
- abi: STAKING_ABI,
223
- functionName: "validatorJoin",
224
- });
225
-
226
- const result = await executeWrite({to: stakingAddress, data, value: amount});
227
- const receipt = await publicClient.getTransactionReceipt({hash: result.transactionHash});
228
-
229
- let validatorWallet: Address | undefined;
230
- let eventFound = false;
231
- for (const log of receipt.logs) {
232
- try {
233
- const decoded = decodeEventLog({abi: STAKING_ABI, data: log.data, topics: log.topics});
234
- if (decoded.eventName === "ValidatorJoin") {
235
- validatorWallet = (decoded.args as {validator: Address}).validator;
236
- eventFound = true;
237
- break;
238
- }
239
- } catch {
240
- // Not a ValidatorJoin event - continue searching
241
- }
242
- }
243
-
244
- if (!eventFound) {
245
- throw new Error(
246
- `ValidatorJoin event not found in transaction ${result.transactionHash}. ` +
247
- `Transaction succeeded but validator wallet address could not be determined.`,
248
- );
249
- }
250
-
251
- return {
252
- transactionHash: receipt.transactionHash,
253
- blockNumber: receipt.blockNumber,
254
- gasUsed: receipt.gasUsed,
255
- validatorWallet: validatorWallet!,
256
- operator: options.operator || (client.account!.address as Address),
257
- amount: formatStakingAmount(amount),
258
- amountRaw: amount,
259
- };
260
- },
261
-
262
- validatorDeposit: async (options: ValidatorDepositOptions): Promise<StakingTransactionResult> => {
263
- const amount = parseStakingAmount(options.amount);
264
- const data = encodeFunctionData({
265
- abi: STAKING_ABI,
266
- functionName: "validatorDeposit",
267
- });
268
- return executeWrite({to: getStakingAddress(), data, value: amount});
269
- },
270
-
271
- validatorExit: async (options: ValidatorExitOptions): Promise<StakingTransactionResult> => {
272
- const shares = typeof options.shares === "string" ? BigInt(options.shares) : options.shares;
273
- const data = encodeFunctionData({
274
- abi: STAKING_ABI,
275
- functionName: "validatorExit",
276
- args: [shares],
277
- });
278
- return executeWrite({to: getStakingAddress(), data});
279
- },
280
-
281
- validatorClaim: async (options?: ValidatorClaimOptions): Promise<StakingTransactionResult & {claimedAmount: bigint}> => {
282
- if (!options?.validator && !client.account) {
283
- throw new Error("Either provide validator address or initialize client with an account");
284
- }
285
- const validatorAddress = options?.validator || (client.account!.address as Address);
286
- const data = encodeFunctionData({
287
- abi: STAKING_ABI,
288
- functionName: "validatorClaim",
289
- args: [validatorAddress as ViemAddress],
290
- });
291
- const result = await executeWrite({to: getStakingAddress(), data});
292
- // TODO: Parse ClaimAmount from logs if needed
293
- return {...result, claimedAmount: 0n};
294
- },
295
-
296
- validatorPrime: async (options: ValidatorPrimeOptions): Promise<StakingTransactionResult> => {
297
- const data = encodeFunctionData({
298
- abi: STAKING_ABI,
299
- functionName: "validatorPrime",
300
- args: [options.validator as ViemAddress],
301
- });
302
- return executeWrite({to: getStakingAddress(), data});
303
- },
304
-
305
- setOperator: async (options: SetOperatorOptions): Promise<StakingTransactionResult> => {
306
- const data = encodeFunctionData({
307
- abi: VALIDATOR_WALLET_ABI,
308
- functionName: "setOperator",
309
- args: [options.operator as ViemAddress],
310
- });
311
- return executeWrite({to: options.validator as ViemAddress, data});
312
- },
313
-
314
- setIdentity: async (options: SetIdentityOptions): Promise<StakingTransactionResult> => {
315
- let extraCidBytes: `0x${string}` = "0x";
316
- if (options.extraCid) {
317
- if (options.extraCid.startsWith("0x")) {
318
- extraCidBytes = options.extraCid as `0x${string}`;
319
- } else {
320
- extraCidBytes = toHex(new TextEncoder().encode(options.extraCid));
321
- }
322
- }
323
- const data = encodeFunctionData({
324
- abi: VALIDATOR_WALLET_ABI,
325
- functionName: "setIdentity",
326
- args: [
327
- options.moniker,
328
- options.logoUri || "",
329
- options.website || "",
330
- options.description || "",
331
- options.email || "",
332
- options.twitter || "",
333
- options.telegram || "",
334
- options.github || "",
335
- extraCidBytes,
336
- ],
337
- });
338
- return executeWrite({to: options.validator as ViemAddress, data});
339
- },
340
-
341
- delegatorJoin: async (options: DelegatorJoinOptions): Promise<DelegatorJoinResult> => {
342
- const amount = parseStakingAmount(options.amount);
343
- const data = encodeFunctionData({
344
- abi: STAKING_ABI,
345
- functionName: "delegatorJoin",
346
- args: [options.validator as ViemAddress],
347
- });
348
- const result = await executeWrite({to: getStakingAddress(), data, value: amount});
349
-
350
- return {
351
- ...result,
352
- validator: options.validator,
353
- delegator: client.account!.address as Address,
354
- amount: formatStakingAmount(amount),
355
- amountRaw: amount,
356
- };
357
- },
358
-
359
- delegatorExit: async (options: DelegatorExitOptions): Promise<StakingTransactionResult> => {
360
- const shares = typeof options.shares === "string" ? BigInt(options.shares) : options.shares;
361
- const data = encodeFunctionData({
362
- abi: STAKING_ABI,
363
- functionName: "delegatorExit",
364
- args: [options.validator as ViemAddress, shares],
365
- });
366
- return executeWrite({to: getStakingAddress(), data});
367
- },
368
-
369
- delegatorClaim: async (options: DelegatorClaimOptions): Promise<StakingTransactionResult> => {
370
- if (!options.delegator && !client.account) {
371
- throw new Error("Either provide delegator address or initialize client with an account");
372
- }
373
- const delegatorAddress = options.delegator || (client.account!.address as Address);
374
- const data = encodeFunctionData({
375
- abi: STAKING_ABI,
376
- functionName: "delegatorClaim",
377
- args: [delegatorAddress as ViemAddress, options.validator as ViemAddress],
378
- });
379
- return executeWrite({to: getStakingAddress(), data});
380
- },
381
-
382
- isValidator: async (address: Address): Promise<boolean> => {
383
- const contract = getReadOnlyStakingContract();
384
- return contract.read.isValidator([address as ViemAddress]) as Promise<boolean>;
385
- },
386
-
387
- getValidatorInfo: async (validator: Address): Promise<ValidatorInfo> => {
388
- const contract = getReadOnlyStakingContract();
389
-
390
- const isVal = await contract.read.isValidator([validator as ViemAddress]);
391
- if (!isVal) {
392
- throw new Error(`Address ${validator} is not a validator`);
393
- }
394
-
395
- // Get validator wallet contract for owner/operator/identity
396
- const walletContract = getContract({
397
- address: validator as ViemAddress,
398
- abi: VALIDATOR_WALLET_ABI,
399
- client: publicClient,
400
- });
401
-
402
- // Fetch all data in parallel
403
- const [view, owner, operator, identityRaw, currentEpoch] = await Promise.all([
404
- contract.read.validatorView([validator as ViemAddress]) as Promise<any>,
405
- walletContract.read.owner() as Promise<Address>,
406
- walletContract.read.operator() as Promise<Address>,
407
- walletContract.read.getIdentity().catch(() => null) as Promise<any>,
408
- contract.read.epoch() as Promise<bigint>,
409
- ]);
410
-
411
- // Parse identity if available
412
- let identity: ValidatorIdentity | undefined;
413
- if (identityRaw && identityRaw.moniker) {
414
- identity = {
415
- moniker: identityRaw.moniker,
416
- logoUri: identityRaw.logoUri,
417
- website: identityRaw.website,
418
- description: identityRaw.description,
419
- email: identityRaw.email,
420
- twitter: identityRaw.twitter,
421
- telegram: identityRaw.telegram,
422
- github: identityRaw.github,
423
- extraCid: identityRaw.extraCid ? toHex(identityRaw.extraCid) : "",
424
- };
425
- }
426
-
427
- // Validator needs priming if ePrimed < currentEpoch - 1
428
- const needsPriming = currentEpoch > 0n && view.ePrimed < currentEpoch - 1n;
429
-
430
- // Fetch pending self-stake deposits
431
- const depositLen = (await contract.read.validatorDepositLen([validator as ViemAddress])) as bigint;
432
- const pendingDeposits: PendingDeposit[] = [];
433
-
434
- for (let i = 0n; i < depositLen; i++) {
435
- const [epoch, commit] = (await contract.read.validatorDeposit([validator as ViemAddress, i])) as [
436
- bigint,
437
- {input: bigint; output: bigint; epoch: bigint; linkToNextCommit: bigint},
438
- ];
439
- pendingDeposits.push({
440
- epoch,
441
- stake: formatStakingAmount(commit.input),
442
- stakeRaw: commit.input,
443
- shares: commit.output,
444
- });
445
- }
446
-
447
- // Fetch pending self-stake withdrawals
448
- const withdrawalLen = (await contract.read.validatorWithdrawalLen([validator as ViemAddress])) as bigint;
449
- const pendingWithdrawals: PendingWithdrawal[] = [];
450
-
451
- for (let i = 0n; i < withdrawalLen; i++) {
452
- const [epoch, commit] = (await contract.read.validatorWithdrawal([validator as ViemAddress, i])) as [
453
- bigint,
454
- {input: bigint; output: bigint; epoch: bigint; linkToNextCommit: bigint},
455
- ];
456
- pendingWithdrawals.push({
457
- epoch,
458
- shares: commit.input,
459
- stake: formatStakingAmount(commit.output),
460
- stakeRaw: commit.output,
461
- });
462
- }
463
-
464
- return {
465
- address: validator,
466
- owner,
467
- operator,
468
- vStake: formatStakingAmount(view.vStake),
469
- vStakeRaw: view.vStake,
470
- vShares: view.vShares,
471
- dStake: formatStakingAmount(view.dStake),
472
- dStakeRaw: view.dStake,
473
- dShares: view.dShares,
474
- vDeposit: formatStakingAmount(view.vDeposit),
475
- vDepositRaw: view.vDeposit,
476
- vWithdrawal: formatStakingAmount(view.vWithdrawal),
477
- vWithdrawalRaw: view.vWithdrawal,
478
- ePrimed: view.ePrimed,
479
- live: view.live,
480
- banned: view.eBanned > 0n,
481
- bannedEpoch: view.eBanned > 0n ? view.eBanned : undefined,
482
- needsPriming,
483
- identity,
484
- pendingDeposits,
485
- pendingWithdrawals,
486
- };
487
- },
488
-
489
- getStakeInfo: async (delegator: Address, validator: Address): Promise<StakeInfo> => {
490
- const contract = getReadOnlyStakingContract();
491
-
492
- const shares = (await contract.read.sharesOf([delegator as ViemAddress, validator as ViemAddress])) as bigint;
493
- // stakeOf divides by shares, so it fails with division by zero if no shares yet
494
- let stake = 0n;
495
- if (shares > 0n) {
496
- stake = (await contract.read.stakeOf([delegator as ViemAddress, validator as ViemAddress])) as bigint;
497
- }
498
-
499
- // Fetch pending delegator deposits
500
- const depositLen = (await contract.read.delegatorDepositLen([
501
- delegator as ViemAddress,
502
- validator as ViemAddress,
503
- ])) as bigint;
504
- const pendingDeposits: PendingDeposit[] = [];
505
-
506
- for (let i = 0n; i < depositLen; i++) {
507
- const [claim, commit] = (await contract.read.delegatorDeposit([
508
- delegator as ViemAddress,
509
- validator as ViemAddress,
510
- i,
511
- ])) as [
512
- {quantity: bigint; commit: bigint},
513
- {input: bigint; output: bigint; epoch: bigint; linkToNextCommit: bigint},
514
- ];
515
- pendingDeposits.push({
516
- epoch: commit.epoch,
517
- stake: formatStakingAmount(commit.input),
518
- stakeRaw: commit.input,
519
- shares: claim.quantity,
520
- });
521
- }
522
-
523
- // Fetch pending delegator withdrawals
524
- const withdrawalLen = (await contract.read.delegatorWithdrawalLen([
525
- delegator as ViemAddress,
526
- validator as ViemAddress,
527
- ])) as bigint;
528
- const pendingWithdrawals: PendingWithdrawal[] = [];
529
-
530
- for (let i = 0n; i < withdrawalLen; i++) {
531
- const [claim, commit] = (await contract.read.delegatorWithdrawal([
532
- delegator as ViemAddress,
533
- validator as ViemAddress,
534
- i,
535
- ])) as [
536
- {quantity: bigint; commit: bigint},
537
- {input: bigint; output: bigint; epoch: bigint; linkToNextCommit: bigint},
538
- ];
539
- pendingWithdrawals.push({
540
- epoch: commit.epoch,
541
- shares: claim.quantity,
542
- stake: formatStakingAmount(commit.output),
543
- stakeRaw: commit.output,
544
- });
545
- }
546
-
547
- return {
548
- delegator,
549
- validator,
550
- shares,
551
- stake: formatStakingAmount(stake),
552
- stakeRaw: stake,
553
- pendingDeposits,
554
- pendingWithdrawals,
555
- };
556
- },
557
-
558
- getEpochInfo: async (): Promise<EpochInfo> => {
559
- const contract = getReadOnlyStakingContract();
560
-
561
- const [
562
- epoch,
563
- finalized,
564
- validatorMinStake,
565
- delegatorMinStake,
566
- activeCount,
567
- epochMinDuration,
568
- epochZeroMinDuration,
569
- epochOdd,
570
- epochEven,
571
- ] = await Promise.all([
572
- contract.read.epoch() as Promise<bigint>,
573
- contract.read.finalized() as Promise<bigint>,
574
- contract.read.validatorMinStake() as Promise<bigint>,
575
- contract.read.delegatorMinStake() as Promise<bigint>,
576
- contract.read.activeValidatorsCount() as Promise<bigint>,
577
- contract.read.epochMinDuration() as Promise<bigint>,
578
- contract.read.epochZeroMinDuration() as Promise<bigint>,
579
- contract.read.epochOdd() as Promise<any>,
580
- contract.read.epochEven() as Promise<any>,
581
- ]);
582
-
583
- // Current epoch data for next epoch estimate
584
- const currentEpochData = epoch % 2n === 0n ? epochEven : epochOdd;
585
- const currentEpochEnd = currentEpochData.end > 0n;
586
-
587
- // Estimate next epoch: current start + min duration (if epoch hasn't ended)
588
- let nextEpochEstimate: Date | null = null;
589
- if (!currentEpochEnd) {
590
- const duration = epoch === 0n ? epochZeroMinDuration : epochMinDuration;
591
- const estimatedEndMs = Number(currentEpochData.start + duration) * 1000;
592
- nextEpochEstimate = new Date(estimatedEndMs);
593
- }
594
-
595
- return {
596
- currentEpoch: epoch,
597
- lastFinalizedEpoch: finalized,
598
- validatorMinStake: formatStakingAmount(validatorMinStake),
599
- validatorMinStakeRaw: validatorMinStake,
600
- delegatorMinStake: formatStakingAmount(delegatorMinStake),
601
- delegatorMinStakeRaw: delegatorMinStake,
602
- activeValidatorsCount: activeCount,
603
- epochMinDuration,
604
- nextEpochEstimate,
605
- };
606
- },
607
-
608
- getEpochData: async (epochNumber: bigint): Promise<EpochData> => {
609
- const contract = getReadOnlyStakingContract();
610
-
611
- const [currentEpoch, epochOdd, epochEven] = await Promise.all([
612
- contract.read.epoch() as Promise<bigint>,
613
- contract.read.epochOdd() as Promise<any>,
614
- contract.read.epochEven() as Promise<any>,
615
- ]);
616
-
617
- // Epochs alternate between odd/even storage slots
618
- // Current epoch N uses: N % 2 === 0 ? epochEven : epochOdd
619
- // We can only access current epoch and previous epoch (N-1)
620
- if (epochNumber > currentEpoch) {
621
- throw new Error(`Epoch ${epochNumber} has not started yet (current: ${currentEpoch})`);
622
- }
623
- if (epochNumber < currentEpoch - 1n && currentEpoch > 0n) {
624
- throw new Error(`Epoch ${epochNumber} data no longer available (only current and previous epoch stored)`);
625
- }
626
-
627
- const epochData = epochNumber % 2n === 0n ? epochEven : epochOdd;
628
-
629
- return {
630
- start: epochData.start,
631
- end: epochData.end,
632
- inflation: epochData.inflation,
633
- weight: epochData.weight,
634
- weightDeposit: epochData.weightDeposit,
635
- weightWithdrawal: epochData.weightWithdrawal,
636
- vcount: epochData.vcount,
637
- claimed: epochData.claimed,
638
- stakeDeposit: epochData.stakeDeposit,
639
- stakeWithdrawal: epochData.stakeWithdrawal,
640
- slashed: epochData.slashed,
641
- };
642
- },
643
-
644
- getActiveValidators: async (): Promise<Address[]> => {
645
- const contract = getReadOnlyStakingContract();
646
- const validators = (await contract.read.activeValidators()) as Address[];
647
- return validators.filter(v => v !== "0x0000000000000000000000000000000000000000");
648
- },
649
-
650
- getActiveValidatorsCount: async (): Promise<bigint> => {
651
- const contract = getReadOnlyStakingContract();
652
- return contract.read.activeValidatorsCount() as Promise<bigint>;
653
- },
654
-
655
- getQuarantinedValidators: async (): Promise<Address[]> => {
656
- const contract = getReadOnlyStakingContract();
657
- return contract.read.getQuarantinedValidators() as Promise<Address[]>;
658
- },
659
-
660
- getBannedValidators: async (startIndex = 0n, size = 100n): Promise<BannedValidatorInfo[]> => {
661
- const contract = getReadOnlyStakingContract();
662
- const result = (await contract.read.getAllBannedValidators([startIndex, size])) as any[];
663
- return result.map((v: any) => ({
664
- validator: v.validator as Address,
665
- untilEpoch: v.untilEpochBanned,
666
- permanentlyBanned: v.permanentlyBanned,
667
- }));
668
- },
669
-
670
- getQuarantinedValidatorsDetailed: async (startIndex = 0n, size = 100n): Promise<BannedValidatorInfo[]> => {
671
- const contract = getReadOnlyStakingContract();
672
- const result = (await contract.read.getAllQuarantinedValidators([startIndex, size])) as any[];
673
- return result.map((v: any) => ({
674
- validator: v.validator as Address,
675
- untilEpoch: v.untilEpochBanned,
676
- permanentlyBanned: v.permanentlyBanned,
677
- }));
678
- },
679
-
680
- getSlashingAddress: async (): Promise<Address> => {
681
- const contract = getReadOnlyStakingContract();
682
- // contracts() returns tuple: [gen, transactions, idleness, tribunal, slashing, consensus, validatorWalletFactory, nftMinter]
683
- const externalContracts = (await contract.read.contracts()) as readonly ViemAddress[];
684
- return externalContracts[4] as Address; // slashing is at index 4
685
- },
686
-
687
- getStakingContract,
688
- parseStakingAmount,
689
- formatStakingAmount,
690
- };
691
- };
@@ -1,2 +0,0 @@
1
- export {stakingActions} from "./actions";
2
- export {parseStakingAmount, formatStakingAmount} from "./utils";