@spectratools/aborean-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +1309 -12
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4,6 +4,9 @@
4
4
  import { readFileSync } from "fs";
5
5
  import { dirname, resolve } from "path";
6
6
  import { fileURLToPath } from "url";
7
+ import { Cli as Cli4, z as z4 } from "incur";
8
+
9
+ // src/commands/gauges.ts
7
10
  import { Cli, z } from "incur";
8
11
 
9
12
  // src/contracts/abis/CLFactory.abi.json
@@ -119,6 +122,140 @@ var CLFactory_abi_default = [
119
122
  }
120
123
  ];
121
124
 
125
+ // src/contracts/abis/Gauge.abi.json
126
+ var Gauge_abi_default = [
127
+ {
128
+ type: "function",
129
+ name: "stakingToken",
130
+ inputs: [],
131
+ outputs: [{ name: "", type: "address", internalType: "address" }],
132
+ stateMutability: "view"
133
+ },
134
+ {
135
+ type: "function",
136
+ name: "rewardToken",
137
+ inputs: [],
138
+ outputs: [{ name: "", type: "address", internalType: "address" }],
139
+ stateMutability: "view"
140
+ },
141
+ {
142
+ type: "function",
143
+ name: "periodFinish",
144
+ inputs: [],
145
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
146
+ stateMutability: "view"
147
+ },
148
+ {
149
+ type: "function",
150
+ name: "rewardRate",
151
+ inputs: [],
152
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
153
+ stateMutability: "view"
154
+ },
155
+ {
156
+ type: "function",
157
+ name: "lastUpdateTime",
158
+ inputs: [],
159
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
160
+ stateMutability: "view"
161
+ },
162
+ {
163
+ type: "function",
164
+ name: "rewardPerTokenStored",
165
+ inputs: [],
166
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
167
+ stateMutability: "view"
168
+ },
169
+ {
170
+ type: "function",
171
+ name: "totalSupply",
172
+ inputs: [],
173
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
174
+ stateMutability: "view"
175
+ },
176
+ {
177
+ type: "function",
178
+ name: "balanceOf",
179
+ inputs: [{ name: "account", type: "address", internalType: "address" }],
180
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
181
+ stateMutability: "view"
182
+ },
183
+ {
184
+ type: "function",
185
+ name: "earned",
186
+ inputs: [{ name: "account", type: "address", internalType: "address" }],
187
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
188
+ stateMutability: "view"
189
+ },
190
+ {
191
+ type: "function",
192
+ name: "fees0",
193
+ inputs: [],
194
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
195
+ stateMutability: "view"
196
+ },
197
+ {
198
+ type: "function",
199
+ name: "fees1",
200
+ inputs: [],
201
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
202
+ stateMutability: "view"
203
+ },
204
+ {
205
+ type: "function",
206
+ name: "left",
207
+ inputs: [],
208
+ outputs: [{ name: "_left", type: "uint256", internalType: "uint256" }],
209
+ stateMutability: "view"
210
+ }
211
+ ];
212
+
213
+ // src/contracts/abis/Minter.abi.json
214
+ var Minter_abi_default = [
215
+ {
216
+ type: "function",
217
+ name: "WEEK",
218
+ inputs: [],
219
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
220
+ stateMutability: "view"
221
+ },
222
+ {
223
+ type: "function",
224
+ name: "weekly",
225
+ inputs: [],
226
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
227
+ stateMutability: "view"
228
+ },
229
+ {
230
+ type: "function",
231
+ name: "activePeriod",
232
+ inputs: [],
233
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
234
+ stateMutability: "view"
235
+ },
236
+ {
237
+ type: "function",
238
+ name: "epochCount",
239
+ inputs: [],
240
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
241
+ stateMutability: "view"
242
+ },
243
+ {
244
+ type: "function",
245
+ name: "teamRate",
246
+ inputs: [],
247
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
248
+ stateMutability: "view"
249
+ },
250
+ {
251
+ type: "function",
252
+ name: "tailEmissionRate",
253
+ inputs: [],
254
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
255
+ stateMutability: "view"
256
+ }
257
+ ];
258
+
122
259
  // src/contracts/abis/PoolFactory.abi.json
123
260
  var PoolFactory_abi_default = [
124
261
  {
@@ -179,6 +316,59 @@ var PoolFactory_abi_default = [
179
316
  }
180
317
  ];
181
318
 
319
+ // src/contracts/abis/RewardsDistributor.abi.json
320
+ var RewardsDistributor_abi_default = [
321
+ {
322
+ type: "function",
323
+ name: "WEEK",
324
+ inputs: [],
325
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
326
+ stateMutability: "view"
327
+ },
328
+ {
329
+ type: "function",
330
+ name: "startTime",
331
+ inputs: [],
332
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
333
+ stateMutability: "view"
334
+ },
335
+ {
336
+ type: "function",
337
+ name: "timeCursorOf",
338
+ inputs: [{ name: "tokenId", type: "uint256", internalType: "uint256" }],
339
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
340
+ stateMutability: "view"
341
+ },
342
+ {
343
+ type: "function",
344
+ name: "lastTokenTime",
345
+ inputs: [],
346
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
347
+ stateMutability: "view"
348
+ },
349
+ {
350
+ type: "function",
351
+ name: "token",
352
+ inputs: [],
353
+ outputs: [{ name: "", type: "address", internalType: "address" }],
354
+ stateMutability: "view"
355
+ },
356
+ {
357
+ type: "function",
358
+ name: "minter",
359
+ inputs: [],
360
+ outputs: [{ name: "", type: "address", internalType: "address" }],
361
+ stateMutability: "view"
362
+ },
363
+ {
364
+ type: "function",
365
+ name: "claimable",
366
+ inputs: [{ name: "tokenId", type: "uint256", internalType: "uint256" }],
367
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
368
+ stateMutability: "view"
369
+ }
370
+ ];
371
+
182
372
  // src/contracts/abis/Voter.abi.json
183
373
  var Voter_abi_default = [
184
374
  {
@@ -209,6 +399,20 @@ var Voter_abi_default = [
209
399
  outputs: [{ name: "", type: "address", internalType: "address" }],
210
400
  stateMutability: "view"
211
401
  },
402
+ {
403
+ type: "function",
404
+ name: "gaugeToFees",
405
+ inputs: [{ name: "gauge", type: "address", internalType: "address" }],
406
+ outputs: [{ name: "", type: "address", internalType: "address" }],
407
+ stateMutability: "view"
408
+ },
409
+ {
410
+ type: "function",
411
+ name: "gaugeToBribe",
412
+ inputs: [{ name: "gauge", type: "address", internalType: "address" }],
413
+ outputs: [{ name: "", type: "address", internalType: "address" }],
414
+ stateMutability: "view"
415
+ },
212
416
  {
213
417
  type: "function",
214
418
  name: "weights",
@@ -216,6 +420,30 @@ var Voter_abi_default = [
216
420
  outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
217
421
  stateMutability: "view"
218
422
  },
423
+ {
424
+ type: "function",
425
+ name: "votes",
426
+ inputs: [
427
+ { name: "tokenId", type: "uint256", internalType: "uint256" },
428
+ { name: "pool", type: "address", internalType: "address" }
429
+ ],
430
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
431
+ stateMutability: "view"
432
+ },
433
+ {
434
+ type: "function",
435
+ name: "usedWeights",
436
+ inputs: [{ name: "tokenId", type: "uint256", internalType: "uint256" }],
437
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
438
+ stateMutability: "view"
439
+ },
440
+ {
441
+ type: "function",
442
+ name: "lastVoted",
443
+ inputs: [{ name: "tokenId", type: "uint256", internalType: "uint256" }],
444
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
445
+ stateMutability: "view"
446
+ },
219
447
  {
220
448
  type: "function",
221
449
  name: "isAlive",
@@ -265,6 +493,13 @@ var Voter_abi_default = [
265
493
  outputs: [{ name: "", type: "address", internalType: "address" }],
266
494
  stateMutability: "view"
267
495
  },
496
+ {
497
+ type: "function",
498
+ name: "epochGovernor",
499
+ inputs: [],
500
+ outputs: [{ name: "", type: "address", internalType: "address" }],
501
+ stateMutability: "view"
502
+ },
268
503
  {
269
504
  type: "function",
270
505
  name: "emergencyCouncil",
@@ -297,6 +532,51 @@ var VotingEscrow_abi_default = [
297
532
  outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
298
533
  stateMutability: "view"
299
534
  },
535
+ {
536
+ type: "function",
537
+ name: "supply",
538
+ inputs: [],
539
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
540
+ stateMutability: "view"
541
+ },
542
+ {
543
+ type: "function",
544
+ name: "permanentLockBalance",
545
+ inputs: [],
546
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
547
+ stateMutability: "view"
548
+ },
549
+ {
550
+ type: "function",
551
+ name: "epoch",
552
+ inputs: [],
553
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
554
+ stateMutability: "view"
555
+ },
556
+ {
557
+ type: "function",
558
+ name: "pointHistory",
559
+ inputs: [{ name: "_loc", type: "uint256", internalType: "uint256" }],
560
+ outputs: [
561
+ {
562
+ name: "",
563
+ type: "tuple",
564
+ internalType: "struct IVotingEscrow.GlobalPoint",
565
+ components: [
566
+ { name: "bias", type: "int128", internalType: "int128" },
567
+ { name: "slope", type: "int128", internalType: "int128" },
568
+ { name: "ts", type: "uint256", internalType: "uint256" },
569
+ { name: "blk", type: "uint256", internalType: "uint256" },
570
+ {
571
+ name: "permanentLockBalance",
572
+ type: "uint256",
573
+ internalType: "uint256"
574
+ }
575
+ ]
576
+ }
577
+ ],
578
+ stateMutability: "view"
579
+ },
300
580
  {
301
581
  type: "function",
302
582
  name: "balanceOf",
@@ -345,21 +625,56 @@ var VotingEscrow_abi_default = [
345
625
  inputs: [],
346
626
  outputs: [{ name: "", type: "address", internalType: "address" }],
347
627
  stateMutability: "view"
348
- },
628
+ }
629
+ ];
630
+
631
+ // src/contracts/abis/VotingReward.abi.json
632
+ var VotingReward_abi_default = [
349
633
  {
350
634
  type: "function",
351
- name: "supply",
635
+ name: "rewardsListLength",
352
636
  inputs: [],
353
637
  outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
354
638
  stateMutability: "view"
639
+ },
640
+ {
641
+ type: "function",
642
+ name: "rewards",
643
+ inputs: [{ name: "", type: "uint256", internalType: "uint256" }],
644
+ outputs: [{ name: "", type: "address", internalType: "address" }],
645
+ stateMutability: "view"
646
+ },
647
+ {
648
+ type: "function",
649
+ name: "tokenRewardsPerEpoch",
650
+ inputs: [
651
+ { name: "token", type: "address", internalType: "address" },
652
+ { name: "epochStart", type: "uint256", internalType: "uint256" }
653
+ ],
654
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
655
+ stateMutability: "view"
656
+ },
657
+ {
658
+ type: "function",
659
+ name: "earned",
660
+ inputs: [
661
+ { name: "token", type: "address", internalType: "address" },
662
+ { name: "tokenId", type: "uint256", internalType: "uint256" }
663
+ ],
664
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
665
+ stateMutability: "view"
355
666
  }
356
667
  ];
357
668
 
358
669
  // src/contracts/abis.ts
359
670
  var clFactoryAbi = CLFactory_abi_default;
671
+ var gaugeAbi = Gauge_abi_default;
672
+ var minterAbi = Minter_abi_default;
360
673
  var poolFactoryAbi = PoolFactory_abi_default;
674
+ var rewardsDistributorAbi = RewardsDistributor_abi_default;
361
675
  var voterAbi = Voter_abi_default;
362
676
  var votingEscrowAbi = VotingEscrow_abi_default;
677
+ var votingRewardAbi = VotingReward_abi_default;
363
678
 
364
679
  // src/contracts/addresses.ts
365
680
  var ABOREAN_V2_ADDRESSES = {
@@ -446,6 +761,985 @@ function createAboreanPublicClient(rpcUrl) {
446
761
  });
447
762
  }
448
763
 
764
+ // src/commands/_common.ts
765
+ import { checksumAddress, weiToEth } from "@spectratools/cli-shared";
766
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
767
+ function toChecksum(address) {
768
+ try {
769
+ return checksumAddress(address);
770
+ } catch {
771
+ return address;
772
+ }
773
+ }
774
+ function asNum(value) {
775
+ return Number(value);
776
+ }
777
+ function relTime(unixSeconds) {
778
+ const ts = typeof unixSeconds === "bigint" ? Number(unixSeconds) : unixSeconds;
779
+ if (!Number.isFinite(ts) || ts <= 0) return "n/a";
780
+ const delta = ts - Math.floor(Date.now() / 1e3);
781
+ const abs = Math.abs(delta);
782
+ const hours = Math.floor(abs / 3600);
783
+ const minutes = Math.floor(abs % 3600 / 60);
784
+ const label = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
785
+ return delta >= 0 ? `in ${label}` : `${label} ago`;
786
+ }
787
+ function clampPositive(seconds) {
788
+ return seconds > 0 ? seconds : 0;
789
+ }
790
+
791
+ // src/commands/gauges.ts
792
+ var env = z.object({
793
+ ABSTRACT_RPC_URL: z.string().optional().describe("Abstract RPC URL override")
794
+ });
795
+ async function discoverGaugePools(client) {
796
+ const [v2PoolCount, clPoolCount] = await Promise.all([
797
+ client.readContract({
798
+ abi: poolFactoryAbi,
799
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
800
+ functionName: "allPoolsLength"
801
+ }),
802
+ client.readContract({
803
+ abi: clFactoryAbi,
804
+ address: ABOREAN_CL_ADDRESSES.clFactory,
805
+ functionName: "allPoolsLength"
806
+ })
807
+ ]);
808
+ const v2Indices = Array.from({ length: asNum(v2PoolCount) }, (_, i) => BigInt(i));
809
+ const clIndices = Array.from({ length: asNum(clPoolCount) }, (_, i) => BigInt(i));
810
+ const [v2Pools, clPools] = await Promise.all([
811
+ v2Indices.length ? client.multicall({
812
+ allowFailure: false,
813
+ contracts: v2Indices.map((index) => ({
814
+ abi: poolFactoryAbi,
815
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
816
+ functionName: "allPools",
817
+ args: [index]
818
+ }))
819
+ }) : Promise.resolve([]),
820
+ clIndices.length ? client.multicall({
821
+ allowFailure: false,
822
+ contracts: clIndices.map((index) => ({
823
+ abi: clFactoryAbi,
824
+ address: ABOREAN_CL_ADDRESSES.clFactory,
825
+ functionName: "allPools",
826
+ args: [index]
827
+ }))
828
+ }) : Promise.resolve([])
829
+ ]);
830
+ const pools = [...v2Pools, ...clPools];
831
+ if (!pools.length) return [];
832
+ const gauges2 = await client.multicall({
833
+ allowFailure: false,
834
+ contracts: pools.map((pool) => ({
835
+ abi: voterAbi,
836
+ address: ABOREAN_V2_ADDRESSES.voter,
837
+ functionName: "gauges",
838
+ args: [pool]
839
+ }))
840
+ });
841
+ return pools.map((pool, index) => ({ pool, gauge: gauges2[index] })).filter(({ gauge }) => gauge.toLowerCase() !== ZERO_ADDRESS.toLowerCase());
842
+ }
843
+ var gauges = Cli.create("gauges", {
844
+ description: "Inspect Aborean gauge emissions, staking, and user positions."
845
+ });
846
+ gauges.command("list", {
847
+ description: "List active gauges with pool, emissions, and staking stats.",
848
+ env,
849
+ output: z.object({
850
+ gauges: z.array(
851
+ z.object({
852
+ pool: z.string(),
853
+ gauge: z.string(),
854
+ rewardToken: z.string(),
855
+ rewardRate: z.string(),
856
+ totalStaked: z.string(),
857
+ claimableEmissions: z.string(),
858
+ periodFinish: z.number(),
859
+ periodFinishRelative: z.string()
860
+ })
861
+ ),
862
+ count: z.number()
863
+ }),
864
+ examples: [{ description: "List all active gauges and current emissions state" }],
865
+ async run(c) {
866
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
867
+ const gaugePools = await discoverGaugePools(client);
868
+ if (!gaugePools.length) {
869
+ return c.ok({ gauges: [], count: 0 });
870
+ }
871
+ const details = await client.multicall({
872
+ allowFailure: false,
873
+ contracts: gaugePools.flatMap(({ gauge }) => [
874
+ {
875
+ abi: gaugeAbi,
876
+ address: gauge,
877
+ functionName: "rewardToken"
878
+ },
879
+ {
880
+ abi: gaugeAbi,
881
+ address: gauge,
882
+ functionName: "rewardRate"
883
+ },
884
+ {
885
+ abi: gaugeAbi,
886
+ address: gauge,
887
+ functionName: "totalSupply"
888
+ },
889
+ {
890
+ abi: gaugeAbi,
891
+ address: gauge,
892
+ functionName: "periodFinish"
893
+ },
894
+ {
895
+ abi: voterAbi,
896
+ address: ABOREAN_V2_ADDRESSES.voter,
897
+ functionName: "claimable",
898
+ args: [gauge]
899
+ }
900
+ ])
901
+ });
902
+ const items = gaugePools.map(({ pool, gauge }, index) => {
903
+ const offset = index * 5;
904
+ const rewardToken = details[offset];
905
+ const rewardRate = details[offset + 1];
906
+ const totalStaked = details[offset + 2];
907
+ const periodFinish = details[offset + 3];
908
+ const claimableEmissions = details[offset + 4];
909
+ return {
910
+ pool: toChecksum(pool),
911
+ gauge: toChecksum(gauge),
912
+ rewardToken: toChecksum(rewardToken),
913
+ rewardRate: rewardRate.toString(),
914
+ totalStaked: totalStaked.toString(),
915
+ claimableEmissions: claimableEmissions.toString(),
916
+ periodFinish: asNum(periodFinish),
917
+ periodFinishRelative: relTime(periodFinish)
918
+ };
919
+ });
920
+ return c.ok({
921
+ gauges: items,
922
+ count: items.length
923
+ });
924
+ }
925
+ });
926
+ gauges.command("info", {
927
+ description: "Get detailed state for one gauge address.",
928
+ args: z.object({
929
+ gauge: z.string().describe("Gauge contract address")
930
+ }),
931
+ env,
932
+ output: z.object({
933
+ gauge: z.string(),
934
+ pool: z.string(),
935
+ isAlive: z.boolean(),
936
+ stakingToken: z.string(),
937
+ rewardToken: z.string(),
938
+ totalStaked: z.string(),
939
+ rewardRate: z.string(),
940
+ rewardPerTokenStored: z.string(),
941
+ fees0: z.string(),
942
+ fees1: z.string(),
943
+ left: z.string(),
944
+ periodFinish: z.number(),
945
+ periodFinishRelative: z.string(),
946
+ lastUpdateTime: z.number(),
947
+ bribeContract: z.string(),
948
+ feeContract: z.string()
949
+ }),
950
+ examples: [
951
+ {
952
+ args: { gauge: "0x0000000000000000000000000000000000000001" },
953
+ description: "Inspect one gauge in detail"
954
+ }
955
+ ],
956
+ async run(c) {
957
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
958
+ const gauge = c.args.gauge;
959
+ const [
960
+ pool,
961
+ isAlive,
962
+ bribeContract,
963
+ feeContract,
964
+ stakingToken,
965
+ rewardToken,
966
+ totalStaked,
967
+ rewardRate,
968
+ periodFinish,
969
+ lastUpdateTime,
970
+ rewardPerTokenStored,
971
+ fees0,
972
+ fees1,
973
+ left
974
+ ] = await Promise.all([
975
+ client.readContract({
976
+ abi: voterAbi,
977
+ address: ABOREAN_V2_ADDRESSES.voter,
978
+ functionName: "poolForGauge",
979
+ args: [gauge]
980
+ }),
981
+ client.readContract({
982
+ abi: voterAbi,
983
+ address: ABOREAN_V2_ADDRESSES.voter,
984
+ functionName: "isAlive",
985
+ args: [gauge]
986
+ }),
987
+ client.readContract({
988
+ abi: voterAbi,
989
+ address: ABOREAN_V2_ADDRESSES.voter,
990
+ functionName: "gaugeToBribe",
991
+ args: [gauge]
992
+ }),
993
+ client.readContract({
994
+ abi: voterAbi,
995
+ address: ABOREAN_V2_ADDRESSES.voter,
996
+ functionName: "gaugeToFees",
997
+ args: [gauge]
998
+ }),
999
+ client.readContract({
1000
+ abi: gaugeAbi,
1001
+ address: gauge,
1002
+ functionName: "stakingToken"
1003
+ }),
1004
+ client.readContract({
1005
+ abi: gaugeAbi,
1006
+ address: gauge,
1007
+ functionName: "rewardToken"
1008
+ }),
1009
+ client.readContract({
1010
+ abi: gaugeAbi,
1011
+ address: gauge,
1012
+ functionName: "totalSupply"
1013
+ }),
1014
+ client.readContract({
1015
+ abi: gaugeAbi,
1016
+ address: gauge,
1017
+ functionName: "rewardRate"
1018
+ }),
1019
+ client.readContract({
1020
+ abi: gaugeAbi,
1021
+ address: gauge,
1022
+ functionName: "periodFinish"
1023
+ }),
1024
+ client.readContract({
1025
+ abi: gaugeAbi,
1026
+ address: gauge,
1027
+ functionName: "lastUpdateTime"
1028
+ }),
1029
+ client.readContract({
1030
+ abi: gaugeAbi,
1031
+ address: gauge,
1032
+ functionName: "rewardPerTokenStored"
1033
+ }),
1034
+ client.readContract({
1035
+ abi: gaugeAbi,
1036
+ address: gauge,
1037
+ functionName: "fees0"
1038
+ }),
1039
+ client.readContract({
1040
+ abi: gaugeAbi,
1041
+ address: gauge,
1042
+ functionName: "fees1"
1043
+ }),
1044
+ client.readContract({
1045
+ abi: gaugeAbi,
1046
+ address: gauge,
1047
+ functionName: "left"
1048
+ })
1049
+ ]);
1050
+ return c.ok({
1051
+ gauge: toChecksum(gauge),
1052
+ pool: toChecksum(pool),
1053
+ isAlive,
1054
+ stakingToken: toChecksum(stakingToken),
1055
+ rewardToken: toChecksum(rewardToken),
1056
+ totalStaked: totalStaked.toString(),
1057
+ rewardRate: rewardRate.toString(),
1058
+ rewardPerTokenStored: rewardPerTokenStored.toString(),
1059
+ fees0: fees0.toString(),
1060
+ fees1: fees1.toString(),
1061
+ left: left.toString(),
1062
+ periodFinish: asNum(periodFinish),
1063
+ periodFinishRelative: relTime(periodFinish),
1064
+ lastUpdateTime: asNum(lastUpdateTime),
1065
+ bribeContract: toChecksum(bribeContract),
1066
+ feeContract: toChecksum(feeContract)
1067
+ });
1068
+ }
1069
+ });
1070
+ gauges.command("staked", {
1071
+ description: "Show one address staking positions across all gauges.",
1072
+ args: z.object({
1073
+ address: z.string().describe("Wallet address to inspect")
1074
+ }),
1075
+ env,
1076
+ output: z.object({
1077
+ address: z.string(),
1078
+ positions: z.array(
1079
+ z.object({
1080
+ pool: z.string(),
1081
+ gauge: z.string(),
1082
+ rewardToken: z.string(),
1083
+ staked: z.string(),
1084
+ earned: z.string()
1085
+ })
1086
+ ),
1087
+ count: z.number()
1088
+ }),
1089
+ examples: [
1090
+ {
1091
+ args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
1092
+ description: "List gauge positions for a wallet"
1093
+ }
1094
+ ],
1095
+ async run(c) {
1096
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1097
+ const gaugePools = await discoverGaugePools(client);
1098
+ if (!gaugePools.length) {
1099
+ return c.ok({
1100
+ address: toChecksum(c.args.address),
1101
+ positions: [],
1102
+ count: 0
1103
+ });
1104
+ }
1105
+ const positionData = await client.multicall({
1106
+ allowFailure: false,
1107
+ contracts: gaugePools.flatMap(({ gauge }) => [
1108
+ {
1109
+ abi: gaugeAbi,
1110
+ address: gauge,
1111
+ functionName: "balanceOf",
1112
+ args: [c.args.address]
1113
+ },
1114
+ {
1115
+ abi: gaugeAbi,
1116
+ address: gauge,
1117
+ functionName: "earned",
1118
+ args: [c.args.address]
1119
+ },
1120
+ {
1121
+ abi: gaugeAbi,
1122
+ address: gauge,
1123
+ functionName: "rewardToken"
1124
+ }
1125
+ ])
1126
+ });
1127
+ const positions = gaugePools.map(({ pool, gauge }, index) => {
1128
+ const offset = index * 3;
1129
+ const staked = positionData[offset];
1130
+ const earned = positionData[offset + 1];
1131
+ const rewardToken = positionData[offset + 2];
1132
+ return {
1133
+ pool: toChecksum(pool),
1134
+ gauge: toChecksum(gauge),
1135
+ rewardToken: toChecksum(rewardToken),
1136
+ staked,
1137
+ earned
1138
+ };
1139
+ }).filter((position) => position.staked > 0n || position.earned > 0n).map((position) => ({
1140
+ pool: position.pool,
1141
+ gauge: position.gauge,
1142
+ rewardToken: position.rewardToken,
1143
+ staked: position.staked.toString(),
1144
+ earned: position.earned.toString()
1145
+ }));
1146
+ return c.ok({
1147
+ address: toChecksum(c.args.address),
1148
+ positions,
1149
+ count: positions.length
1150
+ });
1151
+ }
1152
+ });
1153
+
1154
+ // src/commands/ve.ts
1155
+ import { Cli as Cli2, z as z2 } from "incur";
1156
+ var env2 = z2.object({
1157
+ ABSTRACT_RPC_URL: z2.string().optional().describe("Abstract RPC URL override")
1158
+ });
1159
+ var ve = Cli2.create("ve", {
1160
+ description: "Inspect Aborean VotingEscrow (veABX) global and per-NFT lock state."
1161
+ });
1162
+ ve.command("stats", {
1163
+ description: "Get global VotingEscrow supply, locks, and decay checkpoint data.",
1164
+ env: env2,
1165
+ output: z2.object({
1166
+ token: z2.string(),
1167
+ totalVotingPower: z2.string(),
1168
+ totalLocked: z2.string(),
1169
+ permanentLocked: z2.string(),
1170
+ epoch: z2.number(),
1171
+ decayBias: z2.string(),
1172
+ decaySlope: z2.string(),
1173
+ lastCheckpointTimestamp: z2.number(),
1174
+ lastCheckpointBlock: z2.number()
1175
+ }),
1176
+ examples: [{ description: "Show global veABX state and decay metrics" }],
1177
+ async run(c) {
1178
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1179
+ const [token, totalVotingPower, totalLocked, permanentLocked, epoch] = await Promise.all([
1180
+ client.readContract({
1181
+ abi: votingEscrowAbi,
1182
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1183
+ functionName: "token"
1184
+ }),
1185
+ client.readContract({
1186
+ abi: votingEscrowAbi,
1187
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1188
+ functionName: "totalSupply"
1189
+ }),
1190
+ client.readContract({
1191
+ abi: votingEscrowAbi,
1192
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1193
+ functionName: "supply"
1194
+ }),
1195
+ client.readContract({
1196
+ abi: votingEscrowAbi,
1197
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1198
+ functionName: "permanentLockBalance"
1199
+ }),
1200
+ client.readContract({
1201
+ abi: votingEscrowAbi,
1202
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1203
+ functionName: "epoch"
1204
+ })
1205
+ ]);
1206
+ const point = await client.readContract({
1207
+ abi: votingEscrowAbi,
1208
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1209
+ functionName: "pointHistory",
1210
+ args: [epoch]
1211
+ });
1212
+ return c.ok({
1213
+ token: toChecksum(token),
1214
+ totalVotingPower: totalVotingPower.toString(),
1215
+ totalLocked: totalLocked.toString(),
1216
+ permanentLocked: permanentLocked.toString(),
1217
+ epoch: asNum(epoch),
1218
+ decayBias: point.bias.toString(),
1219
+ decaySlope: point.slope.toString(),
1220
+ lastCheckpointTimestamp: asNum(point.ts),
1221
+ lastCheckpointBlock: asNum(point.blk)
1222
+ });
1223
+ }
1224
+ });
1225
+ ve.command("lock", {
1226
+ description: "Get lock details and voting power for one veNFT token id.",
1227
+ args: z2.object({
1228
+ tokenId: z2.coerce.number().int().nonnegative().describe("veNFT token id")
1229
+ }),
1230
+ env: env2,
1231
+ output: z2.object({
1232
+ tokenId: z2.number(),
1233
+ owner: z2.string(),
1234
+ amount: z2.string(),
1235
+ unlockTime: z2.number(),
1236
+ isPermanent: z2.boolean(),
1237
+ votingPower: z2.string()
1238
+ }),
1239
+ examples: [{ args: { tokenId: 1 }, description: "Inspect lock details for veNFT #1" }],
1240
+ async run(c) {
1241
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1242
+ const tokenId = BigInt(c.args.tokenId);
1243
+ const [owner, locked, votingPower] = await Promise.all([
1244
+ client.readContract({
1245
+ abi: votingEscrowAbi,
1246
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1247
+ functionName: "ownerOf",
1248
+ args: [tokenId]
1249
+ }),
1250
+ client.readContract({
1251
+ abi: votingEscrowAbi,
1252
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1253
+ functionName: "locked",
1254
+ args: [tokenId]
1255
+ }),
1256
+ client.readContract({
1257
+ abi: votingEscrowAbi,
1258
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1259
+ functionName: "balanceOfNFT",
1260
+ args: [tokenId]
1261
+ })
1262
+ ]);
1263
+ return c.ok({
1264
+ tokenId: c.args.tokenId,
1265
+ owner: toChecksum(owner),
1266
+ amount: locked.amount.toString(),
1267
+ unlockTime: asNum(locked.end),
1268
+ isPermanent: locked.isPermanent,
1269
+ votingPower: votingPower.toString()
1270
+ });
1271
+ }
1272
+ });
1273
+ ve.command("locks", {
1274
+ description: "List all veNFT locks owned by an address.",
1275
+ args: z2.object({
1276
+ address: z2.string().describe("Owner address")
1277
+ }),
1278
+ env: env2,
1279
+ output: z2.object({
1280
+ address: z2.string(),
1281
+ locks: z2.array(
1282
+ z2.object({
1283
+ tokenId: z2.string(),
1284
+ amount: z2.string(),
1285
+ unlockTime: z2.number(),
1286
+ isPermanent: z2.boolean(),
1287
+ votingPower: z2.string()
1288
+ })
1289
+ ),
1290
+ count: z2.number()
1291
+ }),
1292
+ examples: [
1293
+ {
1294
+ args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
1295
+ description: "List all veNFT locks for an address"
1296
+ }
1297
+ ],
1298
+ async run(c) {
1299
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1300
+ const balance = await client.readContract({
1301
+ abi: votingEscrowAbi,
1302
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1303
+ functionName: "balanceOf",
1304
+ args: [c.args.address]
1305
+ });
1306
+ const count = asNum(balance);
1307
+ if (!count) {
1308
+ return c.ok({
1309
+ address: toChecksum(c.args.address),
1310
+ locks: [],
1311
+ count: 0
1312
+ });
1313
+ }
1314
+ const indices = Array.from({ length: count }, (_, i) => BigInt(i));
1315
+ const tokenIds = await client.multicall({
1316
+ allowFailure: false,
1317
+ contracts: indices.map((index) => ({
1318
+ abi: votingEscrowAbi,
1319
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1320
+ functionName: "tokenOfOwnerByIndex",
1321
+ args: [c.args.address, index]
1322
+ }))
1323
+ });
1324
+ const lockData = await client.multicall({
1325
+ allowFailure: false,
1326
+ contracts: tokenIds.flatMap((tokenId) => [
1327
+ {
1328
+ abi: votingEscrowAbi,
1329
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1330
+ functionName: "locked",
1331
+ args: [tokenId]
1332
+ },
1333
+ {
1334
+ abi: votingEscrowAbi,
1335
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1336
+ functionName: "balanceOfNFT",
1337
+ args: [tokenId]
1338
+ }
1339
+ ])
1340
+ });
1341
+ const locks = tokenIds.map((tokenId, index) => {
1342
+ const offset = index * 2;
1343
+ const locked = lockData[offset];
1344
+ const votingPower = lockData[offset + 1];
1345
+ return {
1346
+ tokenId: tokenId.toString(),
1347
+ amount: locked.amount.toString(),
1348
+ unlockTime: asNum(locked.end),
1349
+ isPermanent: locked.isPermanent,
1350
+ votingPower: votingPower.toString()
1351
+ };
1352
+ });
1353
+ return c.ok({
1354
+ address: toChecksum(c.args.address),
1355
+ locks,
1356
+ count: locks.length
1357
+ });
1358
+ }
1359
+ });
1360
+ ve.command("voting-power", {
1361
+ description: "Get current voting power for one veNFT token id.",
1362
+ args: z2.object({
1363
+ tokenId: z2.coerce.number().int().nonnegative().describe("veNFT token id")
1364
+ }),
1365
+ env: env2,
1366
+ output: z2.object({
1367
+ tokenId: z2.number(),
1368
+ votingPower: z2.string()
1369
+ }),
1370
+ examples: [{ args: { tokenId: 1 }, description: "Get current voting power for veNFT #1" }],
1371
+ async run(c) {
1372
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1373
+ const votingPower = await client.readContract({
1374
+ abi: votingEscrowAbi,
1375
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
1376
+ functionName: "balanceOfNFT",
1377
+ args: [BigInt(c.args.tokenId)]
1378
+ });
1379
+ return c.ok({
1380
+ tokenId: c.args.tokenId,
1381
+ votingPower: votingPower.toString()
1382
+ });
1383
+ }
1384
+ });
1385
+
1386
+ // src/commands/voter.ts
1387
+ import { Cli as Cli3, z as z3 } from "incur";
1388
+ var env3 = z3.object({
1389
+ ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
1390
+ });
1391
+ async function discoverPools(client) {
1392
+ const [v2PoolCount, clPoolCount] = await Promise.all([
1393
+ client.readContract({
1394
+ abi: poolFactoryAbi,
1395
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
1396
+ functionName: "allPoolsLength"
1397
+ }),
1398
+ client.readContract({
1399
+ abi: clFactoryAbi,
1400
+ address: ABOREAN_CL_ADDRESSES.clFactory,
1401
+ functionName: "allPoolsLength"
1402
+ })
1403
+ ]);
1404
+ const v2Indices = Array.from({ length: asNum(v2PoolCount) }, (_, i) => BigInt(i));
1405
+ const clIndices = Array.from({ length: asNum(clPoolCount) }, (_, i) => BigInt(i));
1406
+ const [v2Pools, clPools] = await Promise.all([
1407
+ v2Indices.length ? client.multicall({
1408
+ allowFailure: false,
1409
+ contracts: v2Indices.map((index) => ({
1410
+ abi: poolFactoryAbi,
1411
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
1412
+ functionName: "allPools",
1413
+ args: [index]
1414
+ }))
1415
+ }) : Promise.resolve([]),
1416
+ clIndices.length ? client.multicall({
1417
+ allowFailure: false,
1418
+ contracts: clIndices.map((index) => ({
1419
+ abi: clFactoryAbi,
1420
+ address: ABOREAN_CL_ADDRESSES.clFactory,
1421
+ functionName: "allPools",
1422
+ args: [index]
1423
+ }))
1424
+ }) : Promise.resolve([])
1425
+ ]);
1426
+ return [...v2Pools, ...clPools];
1427
+ }
1428
+ var voter = Cli3.create("voter", {
1429
+ description: "Inspect Aborean voter epoch, pool weights, and claimable rewards context."
1430
+ });
1431
+ voter.command("epoch", {
1432
+ description: "Show current emissions epoch timing from Minter.",
1433
+ env: env3,
1434
+ output: z3.object({
1435
+ activePeriod: z3.number(),
1436
+ epochEnd: z3.number(),
1437
+ secondsRemaining: z3.number(),
1438
+ timeRemaining: z3.string(),
1439
+ weekSeconds: z3.number(),
1440
+ epochCount: z3.number(),
1441
+ weeklyEmission: z3.string()
1442
+ }),
1443
+ examples: [{ description: "Inspect current voter epoch boundaries" }],
1444
+ async run(c) {
1445
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1446
+ const [activePeriod, weekSeconds, epochCount, weeklyEmission] = await Promise.all([
1447
+ client.readContract({
1448
+ abi: minterAbi,
1449
+ address: ABOREAN_V2_ADDRESSES.minter,
1450
+ functionName: "activePeriod"
1451
+ }),
1452
+ client.readContract({
1453
+ abi: minterAbi,
1454
+ address: ABOREAN_V2_ADDRESSES.minter,
1455
+ functionName: "WEEK"
1456
+ }),
1457
+ client.readContract({
1458
+ abi: minterAbi,
1459
+ address: ABOREAN_V2_ADDRESSES.minter,
1460
+ functionName: "epochCount"
1461
+ }),
1462
+ client.readContract({
1463
+ abi: minterAbi,
1464
+ address: ABOREAN_V2_ADDRESSES.minter,
1465
+ functionName: "weekly"
1466
+ })
1467
+ ]);
1468
+ const now = Math.floor(Date.now() / 1e3);
1469
+ const epochEnd = asNum(activePeriod + weekSeconds);
1470
+ return c.ok({
1471
+ activePeriod: asNum(activePeriod),
1472
+ epochEnd,
1473
+ secondsRemaining: clampPositive(epochEnd - now),
1474
+ timeRemaining: relTime(activePeriod + weekSeconds),
1475
+ weekSeconds: asNum(weekSeconds),
1476
+ epochCount: asNum(epochCount),
1477
+ weeklyEmission: weeklyEmission.toString()
1478
+ });
1479
+ }
1480
+ });
1481
+ voter.command("weights", {
1482
+ description: "Show current pool voting weight distribution.",
1483
+ env: env3,
1484
+ output: z3.object({
1485
+ totalWeight: z3.string(),
1486
+ pools: z3.array(
1487
+ z3.object({
1488
+ pool: z3.string(),
1489
+ gauge: z3.string(),
1490
+ weight: z3.string()
1491
+ })
1492
+ ),
1493
+ count: z3.number()
1494
+ }),
1495
+ examples: [{ description: "List all pools with non-zero voting weight" }],
1496
+ async run(c) {
1497
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1498
+ const pools = await discoverPools(client);
1499
+ if (!pools.length) {
1500
+ return c.ok({ totalWeight: "0", pools: [], count: 0 });
1501
+ }
1502
+ const [totalWeight, poolData] = await Promise.all([
1503
+ client.readContract({
1504
+ abi: voterAbi,
1505
+ address: ABOREAN_V2_ADDRESSES.voter,
1506
+ functionName: "totalWeight"
1507
+ }),
1508
+ client.multicall({
1509
+ allowFailure: false,
1510
+ contracts: pools.flatMap((pool) => [
1511
+ {
1512
+ abi: voterAbi,
1513
+ address: ABOREAN_V2_ADDRESSES.voter,
1514
+ functionName: "gauges",
1515
+ args: [pool]
1516
+ },
1517
+ {
1518
+ abi: voterAbi,
1519
+ address: ABOREAN_V2_ADDRESSES.voter,
1520
+ functionName: "weights",
1521
+ args: [pool]
1522
+ }
1523
+ ])
1524
+ })
1525
+ ]);
1526
+ const entries = pools.map((pool, index) => {
1527
+ const offset = index * 2;
1528
+ const gauge = poolData[offset] ?? ZERO_ADDRESS;
1529
+ const weight = poolData[offset + 1] ?? 0n;
1530
+ return {
1531
+ pool,
1532
+ gauge,
1533
+ weight
1534
+ };
1535
+ }).filter(
1536
+ (entry) => entry.gauge.toLowerCase() !== ZERO_ADDRESS.toLowerCase() && entry.weight > 0n
1537
+ ).sort((a, b) => a.weight > b.weight ? -1 : a.weight < b.weight ? 1 : 0).map((entry) => ({
1538
+ pool: toChecksum(entry.pool),
1539
+ gauge: toChecksum(entry.gauge),
1540
+ weight: entry.weight.toString()
1541
+ }));
1542
+ return c.ok({
1543
+ totalWeight: totalWeight.toString(),
1544
+ pools: entries,
1545
+ count: entries.length
1546
+ });
1547
+ }
1548
+ });
1549
+ voter.command("rewards", {
1550
+ description: "Show claimable rebase rewards and voting context for a veNFT.",
1551
+ args: z3.object({
1552
+ tokenId: z3.coerce.number().int().nonnegative().describe("veNFT token id")
1553
+ }),
1554
+ env: env3,
1555
+ output: z3.object({
1556
+ tokenId: z3.number(),
1557
+ rewardToken: z3.string(),
1558
+ claimableRebase: z3.string(),
1559
+ timeCursor: z3.number(),
1560
+ lastTokenTime: z3.number(),
1561
+ distributorStartTime: z3.number(),
1562
+ usedWeight: z3.string(),
1563
+ lastVoted: z3.number()
1564
+ }),
1565
+ examples: [{ args: { tokenId: 1 }, description: "Check claimable voter/distributor rewards" }],
1566
+ async run(c) {
1567
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1568
+ const tokenId = BigInt(c.args.tokenId);
1569
+ const [
1570
+ rewardToken,
1571
+ claimableRebase,
1572
+ timeCursor,
1573
+ lastTokenTime,
1574
+ distributorStartTime,
1575
+ usedWeight,
1576
+ lastVoted
1577
+ ] = await Promise.all([
1578
+ client.readContract({
1579
+ abi: rewardsDistributorAbi,
1580
+ address: ABOREAN_V2_ADDRESSES.rewardsDistributor,
1581
+ functionName: "token"
1582
+ }),
1583
+ client.readContract({
1584
+ abi: rewardsDistributorAbi,
1585
+ address: ABOREAN_V2_ADDRESSES.rewardsDistributor,
1586
+ functionName: "claimable",
1587
+ args: [tokenId]
1588
+ }),
1589
+ client.readContract({
1590
+ abi: rewardsDistributorAbi,
1591
+ address: ABOREAN_V2_ADDRESSES.rewardsDistributor,
1592
+ functionName: "timeCursorOf",
1593
+ args: [tokenId]
1594
+ }),
1595
+ client.readContract({
1596
+ abi: rewardsDistributorAbi,
1597
+ address: ABOREAN_V2_ADDRESSES.rewardsDistributor,
1598
+ functionName: "lastTokenTime"
1599
+ }),
1600
+ client.readContract({
1601
+ abi: rewardsDistributorAbi,
1602
+ address: ABOREAN_V2_ADDRESSES.rewardsDistributor,
1603
+ functionName: "startTime"
1604
+ }),
1605
+ client.readContract({
1606
+ abi: voterAbi,
1607
+ address: ABOREAN_V2_ADDRESSES.voter,
1608
+ functionName: "usedWeights",
1609
+ args: [tokenId]
1610
+ }),
1611
+ client.readContract({
1612
+ abi: voterAbi,
1613
+ address: ABOREAN_V2_ADDRESSES.voter,
1614
+ functionName: "lastVoted",
1615
+ args: [tokenId]
1616
+ })
1617
+ ]);
1618
+ return c.ok({
1619
+ tokenId: c.args.tokenId,
1620
+ rewardToken: toChecksum(rewardToken),
1621
+ claimableRebase: claimableRebase.toString(),
1622
+ timeCursor: asNum(timeCursor),
1623
+ lastTokenTime: asNum(lastTokenTime),
1624
+ distributorStartTime: asNum(distributorStartTime),
1625
+ usedWeight: usedWeight.toString(),
1626
+ lastVoted: asNum(lastVoted)
1627
+ });
1628
+ }
1629
+ });
1630
+ voter.command("bribes", {
1631
+ description: "Show active bribe reward tokens and current-epoch amounts for a pool.",
1632
+ args: z3.object({
1633
+ pool: z3.string().describe("Pool address")
1634
+ }),
1635
+ env: env3,
1636
+ output: z3.object({
1637
+ pool: z3.string(),
1638
+ gauge: z3.string(),
1639
+ bribeContract: z3.string(),
1640
+ epochStart: z3.number(),
1641
+ rewardTokens: z3.array(
1642
+ z3.object({
1643
+ token: z3.string(),
1644
+ epochAmount: z3.string()
1645
+ })
1646
+ ),
1647
+ count: z3.number()
1648
+ }),
1649
+ examples: [
1650
+ {
1651
+ args: { pool: "0x0000000000000000000000000000000000000001" },
1652
+ description: "Inspect bribe reward tokens for one pool"
1653
+ }
1654
+ ],
1655
+ async run(c) {
1656
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1657
+ const [gauge, epochStart] = await Promise.all([
1658
+ client.readContract({
1659
+ abi: voterAbi,
1660
+ address: ABOREAN_V2_ADDRESSES.voter,
1661
+ functionName: "gauges",
1662
+ args: [c.args.pool]
1663
+ }),
1664
+ client.readContract({
1665
+ abi: minterAbi,
1666
+ address: ABOREAN_V2_ADDRESSES.minter,
1667
+ functionName: "activePeriod"
1668
+ })
1669
+ ]);
1670
+ if (gauge.toLowerCase() === ZERO_ADDRESS.toLowerCase()) {
1671
+ return c.error({
1672
+ code: "NOT_FOUND",
1673
+ message: `No gauge exists for pool ${c.args.pool}`,
1674
+ retryable: false
1675
+ });
1676
+ }
1677
+ const bribeContract = await client.readContract({
1678
+ abi: voterAbi,
1679
+ address: ABOREAN_V2_ADDRESSES.voter,
1680
+ functionName: "gaugeToBribe",
1681
+ args: [gauge]
1682
+ });
1683
+ if (bribeContract.toLowerCase() === ZERO_ADDRESS.toLowerCase()) {
1684
+ return c.ok({
1685
+ pool: toChecksum(c.args.pool),
1686
+ gauge: toChecksum(gauge),
1687
+ bribeContract: toChecksum(bribeContract),
1688
+ epochStart: asNum(epochStart),
1689
+ rewardTokens: [],
1690
+ count: 0
1691
+ });
1692
+ }
1693
+ const rewardsLength = await client.readContract({
1694
+ abi: votingRewardAbi,
1695
+ address: bribeContract,
1696
+ functionName: "rewardsListLength"
1697
+ });
1698
+ const tokenCount = asNum(rewardsLength);
1699
+ if (!tokenCount) {
1700
+ return c.ok({
1701
+ pool: toChecksum(c.args.pool),
1702
+ gauge: toChecksum(gauge),
1703
+ bribeContract: toChecksum(bribeContract),
1704
+ epochStart: asNum(epochStart),
1705
+ rewardTokens: [],
1706
+ count: 0
1707
+ });
1708
+ }
1709
+ const tokenIndices = Array.from({ length: tokenCount }, (_, i) => BigInt(i));
1710
+ const rewardTokens = await client.multicall({
1711
+ allowFailure: false,
1712
+ contracts: tokenIndices.map((index) => ({
1713
+ abi: votingRewardAbi,
1714
+ address: bribeContract,
1715
+ functionName: "rewards",
1716
+ args: [index]
1717
+ }))
1718
+ });
1719
+ const epochAmounts = await client.multicall({
1720
+ allowFailure: false,
1721
+ contracts: rewardTokens.map((token) => ({
1722
+ abi: votingRewardAbi,
1723
+ address: bribeContract,
1724
+ functionName: "tokenRewardsPerEpoch",
1725
+ args: [token, epochStart]
1726
+ }))
1727
+ });
1728
+ const items = rewardTokens.map((token, index) => ({
1729
+ token: toChecksum(token),
1730
+ epochAmount: epochAmounts[index].toString()
1731
+ }));
1732
+ return c.ok({
1733
+ pool: toChecksum(c.args.pool),
1734
+ gauge: toChecksum(gauge),
1735
+ bribeContract: toChecksum(bribeContract),
1736
+ epochStart: asNum(epochStart),
1737
+ rewardTokens: items,
1738
+ count: items.length
1739
+ });
1740
+ }
1741
+ });
1742
+
449
1743
  // src/error-handling.ts
450
1744
  import { AsyncLocalStorage } from "async_hooks";
451
1745
  import { Errors } from "incur";
@@ -576,23 +1870,26 @@ function applyFriendlyErrorHandling(cli2) {
576
1870
  // src/cli.ts
577
1871
  var __dirname = dirname(fileURLToPath(import.meta.url));
578
1872
  var pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
579
- var cli = Cli.create("aborean", {
1873
+ var cli = Cli4.create("aborean", {
580
1874
  version: pkg.version,
581
1875
  description: "Aborean Finance DEX CLI for Abstract chain."
582
1876
  });
583
- var rootEnv = z.object({
584
- ABSTRACT_RPC_URL: z.string().optional().describe("Abstract RPC URL override")
1877
+ cli.command(gauges);
1878
+ cli.command(ve);
1879
+ cli.command(voter);
1880
+ var rootEnv = z4.object({
1881
+ ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
585
1882
  });
586
1883
  cli.command("status", {
587
1884
  description: "Get a cross-contract Aborean protocol snapshot (pool counts, gauge count, veABX supply).",
588
1885
  env: rootEnv,
589
- output: z.object({
590
- v2PoolCount: z.number().describe("Number of V2 AMM pools"),
591
- clPoolCount: z.number().describe("Number of Slipstream (CL) pools"),
592
- gaugeCount: z.number().describe("Number of pools with gauges"),
593
- totalVotingWeight: z.string().describe("Total voting weight (wei)"),
594
- veABXTotalSupply: z.string().describe("Total veABX supply (wei)"),
595
- veABXLockedSupply: z.string().describe("Total ABX locked in VotingEscrow (wei)")
1886
+ output: z4.object({
1887
+ v2PoolCount: z4.number().describe("Number of V2 AMM pools"),
1888
+ clPoolCount: z4.number().describe("Number of Slipstream (CL) pools"),
1889
+ gaugeCount: z4.number().describe("Number of pools with gauges"),
1890
+ totalVotingWeight: z4.string().describe("Total voting weight (wei)"),
1891
+ veABXTotalSupply: z4.string().describe("Total veABX supply (wei)"),
1892
+ veABXLockedSupply: z4.string().describe("Total ABX locked in VotingEscrow (wei)")
596
1893
  }),
597
1894
  examples: [{ description: "Fetch the current Aborean protocol status" }],
598
1895
  async run(c) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectratools/aborean-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for Aborean Finance DEX on Abstract (pools, swaps, gauges, voting escrow).",
5
5
  "type": "module",
6
6
  "license": "MIT",