@hypurrquant/defi-core 0.5.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.
@@ -0,0 +1,709 @@
1
+ import { Address, Hex, PublicClient } from 'viem';
2
+
3
+ /** A built DeFi transaction ready for simulation or broadcast */
4
+ interface DeFiTx {
5
+ description: string;
6
+ to: Address;
7
+ data: Hex;
8
+ value: bigint;
9
+ gas_estimate?: number;
10
+ /** ERC20 approvals to check and send before broadcasting this tx */
11
+ approvals?: Array<{
12
+ token: Address;
13
+ spender: Address;
14
+ amount: bigint;
15
+ }>;
16
+ /** Pre-transactions to execute before the main tx (e.g. farming approval) */
17
+ pre_txs?: DeFiTx[];
18
+ }
19
+ /** Result of executing or simulating a transaction */
20
+ interface ActionResult {
21
+ tx_hash?: string;
22
+ status: TxStatus;
23
+ gas_used?: number;
24
+ description: string;
25
+ details: Record<string, unknown>;
26
+ }
27
+ /** Transaction status (serde: snake_case) */
28
+ declare enum TxStatus {
29
+ DryRun = "dry_run",
30
+ Simulated = "simulated",
31
+ SimulationFailed = "simulation_failed",
32
+ NeedsApproval = "needs_approval",
33
+ Pending = "pending",
34
+ Confirmed = "confirmed",
35
+ Failed = "failed"
36
+ }
37
+ /** Token amount with decimals-aware formatting */
38
+ interface TokenAmount {
39
+ token: Address;
40
+ symbol: string;
41
+ amount: bigint;
42
+ decimals: number;
43
+ }
44
+ declare function formatHuman(t: TokenAmount): string;
45
+ /** Slippage tolerance in basis points */
46
+ interface Slippage {
47
+ bps: number;
48
+ }
49
+ declare function newSlippage(bps: number): Slippage;
50
+ declare function defaultSwapSlippage(): Slippage;
51
+ declare function applyMinSlippage(slippage: Slippage, amount: bigint): bigint;
52
+ interface PriceData {
53
+ source: string;
54
+ source_type: string;
55
+ asset: Address;
56
+ price_usd: bigint;
57
+ price_f64: number;
58
+ block_number?: number;
59
+ timestamp?: number;
60
+ }
61
+ interface SwapParams {
62
+ protocol: string;
63
+ token_in: Address;
64
+ token_out: Address;
65
+ amount_in: bigint;
66
+ slippage: Slippage;
67
+ recipient: Address;
68
+ deadline?: number;
69
+ }
70
+ interface QuoteParams {
71
+ protocol: string;
72
+ token_in: Address;
73
+ token_out: Address;
74
+ amount_in: bigint;
75
+ }
76
+ interface QuoteResult {
77
+ protocol: string;
78
+ amount_out: bigint;
79
+ price_impact_bps?: number;
80
+ fee_bps?: number;
81
+ route: string[];
82
+ }
83
+ interface AddLiquidityParams {
84
+ protocol: string;
85
+ token_a: Address;
86
+ token_b: Address;
87
+ amount_a: bigint;
88
+ amount_b: bigint;
89
+ recipient: Address;
90
+ /** Optional lower tick for concentrated LP (defaults to full range) */
91
+ tick_lower?: number;
92
+ /** Optional upper tick for concentrated LP (defaults to full range) */
93
+ tick_upper?: number;
94
+ /** ±N% concentrated range around current price (e.g. 2 for ±2%) */
95
+ range_pct?: number;
96
+ /** Optional pool address for tick detection / single-side LP */
97
+ pool?: Address;
98
+ }
99
+ interface RemoveLiquidityParams {
100
+ protocol: string;
101
+ token_a: Address;
102
+ token_b: Address;
103
+ liquidity: bigint;
104
+ recipient: Address;
105
+ }
106
+ interface SupplyParams {
107
+ protocol: string;
108
+ asset: Address;
109
+ amount: bigint;
110
+ on_behalf_of: Address;
111
+ }
112
+ interface BorrowParams {
113
+ protocol: string;
114
+ asset: Address;
115
+ amount: bigint;
116
+ interest_rate_mode: InterestRateMode;
117
+ on_behalf_of: Address;
118
+ }
119
+ /** Interest rate mode (serde: snake_case) */
120
+ declare enum InterestRateMode {
121
+ Variable = "variable",
122
+ Stable = "stable"
123
+ }
124
+ interface RepayParams {
125
+ protocol: string;
126
+ asset: Address;
127
+ amount: bigint;
128
+ interest_rate_mode: InterestRateMode;
129
+ on_behalf_of: Address;
130
+ }
131
+ interface WithdrawParams {
132
+ protocol: string;
133
+ asset: Address;
134
+ amount: bigint;
135
+ to: Address;
136
+ }
137
+ interface LendingRates {
138
+ protocol: string;
139
+ asset: Address;
140
+ supply_apy: number;
141
+ borrow_variable_apy: number;
142
+ borrow_stable_apy?: number;
143
+ utilization: number;
144
+ total_supply: bigint;
145
+ total_borrow: bigint;
146
+ /** Reward token addresses for supply-side incentives */
147
+ supply_reward_tokens?: string[];
148
+ /** Reward token addresses for borrow-side incentives */
149
+ borrow_reward_tokens?: string[];
150
+ /** Emissions per second per supply reward token (raw uint256 as string) */
151
+ supply_emissions_per_second?: string[];
152
+ /** Emissions per second per borrow reward token (raw uint256 as string) */
153
+ borrow_emissions_per_second?: string[];
154
+ /** Supply-side incentive APY (%) from reward token emissions */
155
+ supply_incentive_apy?: number;
156
+ /** Borrow-side incentive APY (%) from reward token emissions (negative = subsidized) */
157
+ borrow_incentive_apy?: number;
158
+ }
159
+ interface UserPosition {
160
+ protocol: string;
161
+ user: Address;
162
+ supplies: PositionAsset[];
163
+ borrows: PositionAsset[];
164
+ health_factor?: number;
165
+ net_apy?: number;
166
+ }
167
+ interface PositionAsset {
168
+ asset: Address;
169
+ symbol: string;
170
+ amount: bigint;
171
+ value_usd?: number;
172
+ }
173
+ interface OpenCdpParams {
174
+ protocol: string;
175
+ collateral: Address;
176
+ collateral_amount: bigint;
177
+ debt_amount: bigint;
178
+ recipient: Address;
179
+ }
180
+ interface AdjustCdpParams {
181
+ protocol: string;
182
+ cdp_id: bigint;
183
+ collateral_delta?: bigint;
184
+ debt_delta?: bigint;
185
+ add_collateral: boolean;
186
+ add_debt: boolean;
187
+ }
188
+ interface CloseCdpParams {
189
+ protocol: string;
190
+ cdp_id: bigint;
191
+ }
192
+ interface CdpInfo {
193
+ protocol: string;
194
+ cdp_id: bigint;
195
+ collateral: TokenAmount;
196
+ debt: TokenAmount;
197
+ collateral_ratio: number;
198
+ liquidation_price?: number;
199
+ }
200
+ interface StakeParams {
201
+ protocol: string;
202
+ amount: bigint;
203
+ recipient: Address;
204
+ }
205
+ interface UnstakeParams {
206
+ protocol: string;
207
+ amount: bigint;
208
+ recipient: Address;
209
+ }
210
+ interface StakingInfo {
211
+ protocol: string;
212
+ staked_token: Address;
213
+ liquid_token: Address;
214
+ exchange_rate: number;
215
+ apy?: number;
216
+ total_staked: bigint;
217
+ }
218
+ interface VaultInfo {
219
+ protocol: string;
220
+ vault_address: Address;
221
+ asset: Address;
222
+ total_assets: bigint;
223
+ total_supply: bigint;
224
+ apy?: number;
225
+ }
226
+ interface DerivativesPositionParams {
227
+ protocol: string;
228
+ market: string;
229
+ size: bigint;
230
+ collateral: bigint;
231
+ is_long: boolean;
232
+ }
233
+ interface OptionParams {
234
+ protocol: string;
235
+ underlying: Address;
236
+ strike_price: bigint;
237
+ expiry: number;
238
+ is_call: boolean;
239
+ amount: bigint;
240
+ }
241
+ /** A pool that has an active emission gauge */
242
+ interface GaugedPool {
243
+ pool: Address;
244
+ gauge: Address;
245
+ token0: string;
246
+ token1: string;
247
+ token0Addr?: Address;
248
+ token1Addr?: Address;
249
+ type: "V2" | "CL";
250
+ tickSpacing?: number;
251
+ stable?: boolean;
252
+ /** Reward rate in wei per second (from gauge.rewardRate or rewardData) */
253
+ rewardRate?: bigint;
254
+ /** Total LP staked in gauge (wei) */
255
+ totalStaked?: bigint;
256
+ /** Reward token address */
257
+ rewardToken?: Address;
258
+ /** Calculated emission APR (%) — set by caller if prices available */
259
+ aprPercent?: number;
260
+ /** Pool TVL in USD — set by caller if prices available */
261
+ poolTvlUsd?: number;
262
+ }
263
+ interface RewardInfo {
264
+ token: Address;
265
+ symbol: string;
266
+ amount: bigint;
267
+ value_usd?: number;
268
+ }
269
+ interface GaugeInfo {
270
+ gauge: Address;
271
+ pool: Address;
272
+ total_staked: bigint;
273
+ reward_rate: bigint;
274
+ rewards: RewardInfo[];
275
+ }
276
+ interface VeNftInfo {
277
+ token_id: bigint;
278
+ amount: bigint;
279
+ unlock_time: number;
280
+ voting_power: bigint;
281
+ }
282
+ interface YieldInfo {
283
+ protocol: string;
284
+ pool: string;
285
+ apy: number;
286
+ tvl: bigint;
287
+ tokens: Address[];
288
+ }
289
+ interface PortfolioSnapshot {
290
+ timestamp: number;
291
+ chain: string;
292
+ wallet: string;
293
+ tokens: TokenBalance[];
294
+ defi_positions: DefiPosition[];
295
+ total_value_usd: number;
296
+ }
297
+ interface TokenBalance {
298
+ token: string;
299
+ symbol: string;
300
+ balance: bigint;
301
+ value_usd: number;
302
+ price_usd: number;
303
+ }
304
+ interface DefiPosition {
305
+ protocol: string;
306
+ type: "lending_supply" | "lending_borrow" | "lp" | "staking" | "vault";
307
+ asset: string;
308
+ amount: bigint;
309
+ value_usd: number;
310
+ }
311
+ interface PortfolioPnL {
312
+ period: string;
313
+ start_value_usd: number;
314
+ end_value_usd: number;
315
+ pnl_usd: number;
316
+ pnl_pct: number;
317
+ token_changes: TokenChange[];
318
+ }
319
+ interface TokenChange {
320
+ symbol: string;
321
+ balance_change: bigint;
322
+ value_change_usd: number;
323
+ }
324
+
325
+ type DefiErrorCode = "PROTOCOL_NOT_FOUND" | "TOKEN_NOT_FOUND" | "CHAIN_NOT_FOUND" | "INSUFFICIENT_BALANCE" | "INSUFFICIENT_ALLOWANCE" | "SLIPPAGE_EXCEEDED" | "SIMULATION_FAILED" | "ABI_ERROR" | "REGISTRY_ERROR" | "RPC_ERROR" | "PROVIDER_ERROR" | "CONTRACT_ERROR" | "INVALID_PARAM" | "UNSUPPORTED" | "TX_FAILED" | "INTERNAL";
326
+ declare class DefiError extends Error {
327
+ readonly code: DefiErrorCode;
328
+ constructor(code: DefiErrorCode, message: string);
329
+ static protocolNotFound(name: string): DefiError;
330
+ static tokenNotFound(name: string): DefiError;
331
+ static chainNotFound(name: string): DefiError;
332
+ static insufficientBalance(needed: string, available: string): DefiError;
333
+ static insufficientAllowance(spender: Address): DefiError;
334
+ static slippageExceeded(expected: string, actual: string): DefiError;
335
+ static simulationFailed(reason: string): DefiError;
336
+ static abiError(reason: string): DefiError;
337
+ static registryError(reason: string): DefiError;
338
+ static rpcError(reason: string): DefiError;
339
+ static providerError(reason: string): DefiError;
340
+ static contractError(reason: string): DefiError;
341
+ static invalidParam(reason: string): DefiError;
342
+ static unsupported(operation: string): DefiError;
343
+ static internal(reason: string): DefiError;
344
+ toJSON(): {
345
+ error: string;
346
+ };
347
+ }
348
+ type Result<T> = T;
349
+
350
+ /**
351
+ * BigInt JSON serialization utilities.
352
+ *
353
+ * Rust's alloy U256 (backed by ruint) serializes to JSON as 0x-prefixed
354
+ * lowercase hex strings (e.g., "0x75bcd15"). We must match this exactly
355
+ * for behavioral parity.
356
+ */
357
+ /** JSON replacer for Rust parity — bigint becomes 0x-hex string */
358
+ declare function jsonReplacer(_key: string, value: unknown): unknown;
359
+ /** JSON replacer for SDK consumers — bigint becomes decimal string */
360
+ declare function jsonReplacerDecimal(_key: string, value: unknown): unknown;
361
+ /** Stringify with decimal bigint handling */
362
+ declare function jsonStringify(data: unknown, pretty?: boolean): string;
363
+ /** Parse a 0x-hex or decimal string to bigint */
364
+ declare function parseBigInt(value: string): bigint;
365
+
366
+ declare const erc20Abi: readonly [{
367
+ readonly name: "name";
368
+ readonly type: "function";
369
+ readonly stateMutability: "view";
370
+ readonly inputs: readonly [];
371
+ readonly outputs: readonly [{
372
+ readonly type: "string";
373
+ }];
374
+ }, {
375
+ readonly name: "symbol";
376
+ readonly type: "function";
377
+ readonly stateMutability: "view";
378
+ readonly inputs: readonly [];
379
+ readonly outputs: readonly [{
380
+ readonly type: "string";
381
+ }];
382
+ }, {
383
+ readonly name: "decimals";
384
+ readonly type: "function";
385
+ readonly stateMutability: "view";
386
+ readonly inputs: readonly [];
387
+ readonly outputs: readonly [{
388
+ readonly type: "uint8";
389
+ }];
390
+ }, {
391
+ readonly name: "totalSupply";
392
+ readonly type: "function";
393
+ readonly stateMutability: "view";
394
+ readonly inputs: readonly [];
395
+ readonly outputs: readonly [{
396
+ readonly type: "uint256";
397
+ }];
398
+ }, {
399
+ readonly name: "balanceOf";
400
+ readonly type: "function";
401
+ readonly stateMutability: "view";
402
+ readonly inputs: readonly [{
403
+ readonly type: "address";
404
+ readonly name: "account";
405
+ }];
406
+ readonly outputs: readonly [{
407
+ readonly type: "uint256";
408
+ }];
409
+ }, {
410
+ readonly name: "transfer";
411
+ readonly type: "function";
412
+ readonly stateMutability: "nonpayable";
413
+ readonly inputs: readonly [{
414
+ readonly type: "address";
415
+ readonly name: "to";
416
+ }, {
417
+ readonly type: "uint256";
418
+ readonly name: "amount";
419
+ }];
420
+ readonly outputs: readonly [{
421
+ readonly type: "bool";
422
+ }];
423
+ }, {
424
+ readonly name: "allowance";
425
+ readonly type: "function";
426
+ readonly stateMutability: "view";
427
+ readonly inputs: readonly [{
428
+ readonly type: "address";
429
+ readonly name: "owner";
430
+ }, {
431
+ readonly type: "address";
432
+ readonly name: "spender";
433
+ }];
434
+ readonly outputs: readonly [{
435
+ readonly type: "uint256";
436
+ }];
437
+ }, {
438
+ readonly name: "approve";
439
+ readonly type: "function";
440
+ readonly stateMutability: "nonpayable";
441
+ readonly inputs: readonly [{
442
+ readonly type: "address";
443
+ readonly name: "spender";
444
+ }, {
445
+ readonly type: "uint256";
446
+ readonly name: "amount";
447
+ }];
448
+ readonly outputs: readonly [{
449
+ readonly type: "bool";
450
+ }];
451
+ }, {
452
+ readonly name: "transferFrom";
453
+ readonly type: "function";
454
+ readonly stateMutability: "nonpayable";
455
+ readonly inputs: readonly [{
456
+ readonly type: "address";
457
+ readonly name: "from";
458
+ }, {
459
+ readonly type: "address";
460
+ readonly name: "to";
461
+ }, {
462
+ readonly type: "uint256";
463
+ readonly name: "amount";
464
+ }];
465
+ readonly outputs: readonly [{
466
+ readonly type: "bool";
467
+ }];
468
+ }];
469
+
470
+ declare function buildApprove(token: Address, spender: Address, amount: bigint): DeFiTx;
471
+ declare function buildTransfer(token: Address, to: Address, amount: bigint): DeFiTx;
472
+
473
+ declare function getProvider(rpcUrl: string): PublicClient;
474
+ declare function clearProviderCache(): void;
475
+
476
+ declare const MULTICALL3_ADDRESS: Address;
477
+ declare function buildMulticall(calls: Array<[Address, Hex]>): DeFiTx;
478
+ declare function multicallRead(rpcUrl: string, calls: Array<[Address, Hex]>): Promise<(Hex | null)[]>;
479
+ declare function decodeU256(data: Hex | null): bigint;
480
+ declare function decodeU128(data: Hex | null): bigint;
481
+
482
+ interface IDex {
483
+ name(): string;
484
+ buildSwap(params: SwapParams): Promise<DeFiTx>;
485
+ quote(params: QuoteParams): Promise<QuoteResult>;
486
+ buildAddLiquidity(params: AddLiquidityParams): Promise<DeFiTx>;
487
+ buildRemoveLiquidity(params: RemoveLiquidityParams): Promise<DeFiTx>;
488
+ }
489
+
490
+ interface ILending {
491
+ name(): string;
492
+ buildSupply(params: SupplyParams): Promise<DeFiTx>;
493
+ buildBorrow(params: BorrowParams): Promise<DeFiTx>;
494
+ buildRepay(params: RepayParams): Promise<DeFiTx>;
495
+ buildWithdraw(params: WithdrawParams): Promise<DeFiTx>;
496
+ getRates(asset: Address): Promise<LendingRates>;
497
+ getUserPosition(user: Address): Promise<UserPosition>;
498
+ }
499
+
500
+ /** ve(3,3) Gauge operations — stake LP tokens to earn emissions */
501
+ interface IGauge {
502
+ name(): string;
503
+ /** Resolve gauge address from pool address via voter */
504
+ resolveGauge?(pool: Address): Promise<Address>;
505
+ /** Deposit LP tokens into gauge */
506
+ buildDeposit(gauge: Address, amount: bigint, tokenId?: bigint, lpToken?: Address): Promise<DeFiTx>;
507
+ /** Withdraw LP tokens or NFT from gauge */
508
+ buildWithdraw(gauge: Address, amount: bigint, tokenId?: bigint): Promise<DeFiTx>;
509
+ /** Claim earned rewards from gauge */
510
+ buildClaimRewards(gauge: Address, account?: Address): Promise<DeFiTx>;
511
+ /** Claim rewards for a CL gauge NFT position (Hybra V4 style) */
512
+ buildClaimRewardsByTokenId?(gauge: Address, tokenId: bigint): Promise<DeFiTx>;
513
+ /** Get pending rewards for a user */
514
+ getPendingRewards(gauge: Address, user: Address): Promise<RewardInfo[]>;
515
+ /** Get pending rewards for a CL gauge NFT position */
516
+ getPendingRewardsByTokenId?(gauge: Address, tokenId: bigint): Promise<bigint>;
517
+ /** Get pending rewards for an Aerodrome Slipstream CL gauge using earned(address, uint256) */
518
+ getPendingRewardsByCLTokenId?(gauge: Address, user: Address, tokenId: bigint): Promise<bigint>;
519
+ /** Discover all pools that have active emission gauges */
520
+ discoverGaugedPools?(): Promise<GaugedPool[]>;
521
+ }
522
+ /** ve(3,3) Vote-escrow operations — lock tokens for veNFT */
523
+ interface IVoteEscrow {
524
+ name(): string;
525
+ /** Create a new veNFT lock */
526
+ buildCreateLock(amount: bigint, lockDuration: number): Promise<DeFiTx>;
527
+ /** Increase lock amount */
528
+ buildIncreaseAmount(tokenId: bigint, amount: bigint): Promise<DeFiTx>;
529
+ /** Increase lock duration */
530
+ buildIncreaseUnlockTime(tokenId: bigint, lockDuration: number): Promise<DeFiTx>;
531
+ /** Withdraw after lock expires */
532
+ buildWithdrawExpired(tokenId: bigint): Promise<DeFiTx>;
533
+ }
534
+ /** ve(3,3) Voter operations — vote on gauge emissions */
535
+ interface IVoter {
536
+ name(): string;
537
+ /** Vote for gauges with veNFT */
538
+ buildVote(tokenId: bigint, pools: Address[], weights: bigint[]): Promise<DeFiTx>;
539
+ /** Claim bribes for voted pools */
540
+ buildClaimBribes(bribes: Address[], tokenId: bigint): Promise<DeFiTx>;
541
+ /** Claim trading fees */
542
+ buildClaimFees(fees: Address[], tokenId: bigint): Promise<DeFiTx>;
543
+ }
544
+ /** Combined ve(3,3) system — gauge staking + vote-escrow + voter */
545
+ interface IGaugeSystem extends IGauge, IVoteEscrow, IVoter {
546
+ }
547
+
548
+ /** ERC-4626 Vault interface — covers Capital Allocators, Yield Aggregators, and Yield vaults */
549
+ interface IVault {
550
+ name(): string;
551
+ buildDeposit(assets: bigint, receiver: Address): Promise<DeFiTx>;
552
+ buildWithdraw(assets: bigint, receiver: Address, owner: Address): Promise<DeFiTx>;
553
+ totalAssets(): Promise<bigint>;
554
+ convertToShares(assets: bigint): Promise<bigint>;
555
+ convertToAssets(shares: bigint): Promise<bigint>;
556
+ getVaultInfo(): Promise<VaultInfo>;
557
+ }
558
+
559
+ interface ILiquidStaking {
560
+ name(): string;
561
+ buildStake(params: StakeParams): Promise<DeFiTx>;
562
+ buildUnstake(params: UnstakeParams): Promise<DeFiTx>;
563
+ getInfo(): Promise<StakingInfo>;
564
+ }
565
+
566
+ interface ICdp {
567
+ name(): string;
568
+ buildOpen(params: OpenCdpParams): Promise<DeFiTx>;
569
+ buildAdjust(params: AdjustCdpParams): Promise<DeFiTx>;
570
+ buildClose(params: CloseCdpParams): Promise<DeFiTx>;
571
+ getCdpInfo(cdpId: bigint): Promise<CdpInfo>;
572
+ }
573
+
574
+ /** Oracle price feed — reads prices from lending protocol oracles or price feeds */
575
+ interface IOracle {
576
+ name(): string;
577
+ /** Get price for an asset from this oracle */
578
+ getPrice(asset: Address): Promise<PriceData>;
579
+ /** Get prices for multiple assets */
580
+ getPrices(assets: Address[]): Promise<PriceData[]>;
581
+ }
582
+
583
+ interface IDerivatives {
584
+ name(): string;
585
+ buildOpenPosition(params: DerivativesPositionParams): Promise<DeFiTx>;
586
+ buildClosePosition(params: DerivativesPositionParams): Promise<DeFiTx>;
587
+ }
588
+
589
+ interface IOptions {
590
+ name(): string;
591
+ buildBuy(params: OptionParams): Promise<DeFiTx>;
592
+ buildSell(params: OptionParams): Promise<DeFiTx>;
593
+ }
594
+
595
+ interface IYieldSource {
596
+ name(): string;
597
+ getYields(): Promise<YieldInfo[]>;
598
+ buildDeposit(pool: string, amount: bigint, recipient: Address): Promise<DeFiTx>;
599
+ buildWithdraw(pool: string, amount: bigint, recipient: Address): Promise<DeFiTx>;
600
+ }
601
+
602
+ interface IYieldAggregator {
603
+ name(): string;
604
+ getVaults(): Promise<VaultInfo[]>;
605
+ buildDeposit(vault: Address, amount: bigint, recipient: Address): Promise<DeFiTx>;
606
+ buildWithdraw(vault: Address, amount: bigint, recipient: Address, owner: Address): Promise<DeFiTx>;
607
+ }
608
+
609
+ interface NftCollectionInfo {
610
+ address: Address;
611
+ name: string;
612
+ symbol: string;
613
+ total_supply?: bigint;
614
+ floor_price?: bigint;
615
+ floor_price_currency?: string;
616
+ }
617
+ interface NftTokenInfo {
618
+ collection: Address;
619
+ token_id: bigint;
620
+ owner: Address;
621
+ token_uri?: string;
622
+ }
623
+ interface INft {
624
+ name(): string;
625
+ getCollectionInfo(collection: Address): Promise<NftCollectionInfo>;
626
+ getTokenInfo(collection: Address, tokenId: bigint): Promise<NftTokenInfo>;
627
+ getBalance(owner: Address, collection: Address): Promise<bigint>;
628
+ }
629
+
630
+ declare class ChainConfig {
631
+ name: string;
632
+ chain_id: number;
633
+ rpc_url: string;
634
+ explorer_url?: string;
635
+ native_token: string;
636
+ wrapped_native?: string;
637
+ multicall3?: string;
638
+ effectiveRpcUrl(): string;
639
+ }
640
+
641
+ interface TokenEntry {
642
+ symbol: string;
643
+ name: string;
644
+ address: Address;
645
+ decimals: number;
646
+ is_native_wrapper?: boolean;
647
+ tags?: string[];
648
+ }
649
+
650
+ declare enum ProtocolCategory {
651
+ Dex = "dex",
652
+ Lending = "lending",
653
+ Cdp = "cdp",
654
+ Bridge = "bridge",
655
+ LiquidStaking = "liquid_staking",
656
+ YieldSource = "yield_source",
657
+ YieldAggregator = "yield_aggregator",
658
+ Vault = "vault",
659
+ Derivatives = "derivatives",
660
+ Options = "options",
661
+ LiquidityManager = "liquidity_manager",
662
+ Nft = "nft",
663
+ Other = "other"
664
+ }
665
+ declare function protocolCategoryLabel(category: ProtocolCategory): string;
666
+ interface PoolInfo {
667
+ name: string;
668
+ address: Address;
669
+ token0: string;
670
+ token1: string;
671
+ tick_spacing?: number;
672
+ gauge?: Address;
673
+ stable?: boolean;
674
+ }
675
+ interface ProtocolEntry {
676
+ name: string;
677
+ slug: string;
678
+ category: ProtocolCategory;
679
+ interface: string;
680
+ chain: string;
681
+ native?: boolean;
682
+ verified?: boolean;
683
+ contracts?: Record<string, Address>;
684
+ pools?: PoolInfo[];
685
+ description?: string;
686
+ }
687
+
688
+ declare class Registry {
689
+ chains: Map<string, ChainConfig>;
690
+ tokens: Map<string, TokenEntry[]>;
691
+ protocols: ProtocolEntry[];
692
+ private constructor();
693
+ static loadEmbedded(): Registry;
694
+ private static loadChains;
695
+ private static loadTokens;
696
+ private static loadProtocols;
697
+ getChain(name: string): ChainConfig;
698
+ getProtocol(name: string): ProtocolEntry;
699
+ getProtocolsByCategory(category: ProtocolCategory): ProtocolEntry[];
700
+ getProtocolsForChain(chain: string, includeUnverified?: boolean): ProtocolEntry[];
701
+ resolveToken(chain: string, symbol: string): TokenEntry;
702
+ /**
703
+ * Resolve a pool by name (e.g. "WHYPE/USDC") from a protocol's pool list.
704
+ * Returns the pool info or throws if not found.
705
+ */
706
+ resolvePool(protocolSlug: string, poolName: string): PoolInfo;
707
+ }
708
+
709
+ export { type ActionResult, type AddLiquidityParams, type AdjustCdpParams, type BorrowParams, type CdpInfo, ChainConfig, type CloseCdpParams, type DeFiTx, DefiError, type DefiErrorCode, type DefiPosition, type DerivativesPositionParams, type GaugeInfo, type GaugedPool, type ICdp, type IDerivatives, type IDex, type IGauge, type IGaugeSystem, type ILending, type ILiquidStaking, type INft, type IOptions, type IOracle, type IVault, type IVoteEscrow, type IVoter, type IYieldAggregator, type IYieldSource, InterestRateMode, type LendingRates, MULTICALL3_ADDRESS, type NftCollectionInfo, type NftTokenInfo, type OpenCdpParams, type OptionParams, type PoolInfo, type PortfolioPnL, type PortfolioSnapshot, type PositionAsset, type PriceData, ProtocolCategory, type ProtocolEntry, type QuoteParams, type QuoteResult, Registry, type RemoveLiquidityParams, type RepayParams, type Result, type RewardInfo, type Slippage, type StakeParams, type StakingInfo, type SupplyParams, type SwapParams, type TokenAmount, type TokenBalance, type TokenChange, type TokenEntry, TxStatus, type UnstakeParams, type UserPosition, type VaultInfo, type VeNftInfo, type WithdrawParams, type YieldInfo, applyMinSlippage, buildApprove, buildMulticall, buildTransfer, clearProviderCache, decodeU128, decodeU256, defaultSwapSlippage, erc20Abi, formatHuman, getProvider, jsonReplacer, jsonReplacerDecimal, jsonStringify, multicallRead, newSlippage, parseBigInt, protocolCategoryLabel };
package/dist/index.js ADDED
@@ -0,0 +1,471 @@
1
+ // src/types.ts
2
+ var TxStatus = /* @__PURE__ */ ((TxStatus2) => {
3
+ TxStatus2["DryRun"] = "dry_run";
4
+ TxStatus2["Simulated"] = "simulated";
5
+ TxStatus2["SimulationFailed"] = "simulation_failed";
6
+ TxStatus2["NeedsApproval"] = "needs_approval";
7
+ TxStatus2["Pending"] = "pending";
8
+ TxStatus2["Confirmed"] = "confirmed";
9
+ TxStatus2["Failed"] = "failed";
10
+ return TxStatus2;
11
+ })(TxStatus || {});
12
+ function formatHuman(t) {
13
+ const divisor = 10n ** BigInt(t.decimals);
14
+ const whole = t.amount / divisor;
15
+ const frac = t.amount % divisor;
16
+ return `${whole}.${frac.toString().padStart(t.decimals, "0")} ${t.symbol}`;
17
+ }
18
+ function newSlippage(bps) {
19
+ return { bps };
20
+ }
21
+ function defaultSwapSlippage() {
22
+ return { bps: 50 };
23
+ }
24
+ function applyMinSlippage(slippage, amount) {
25
+ return amount * BigInt(1e4 - slippage.bps) / 10000n;
26
+ }
27
+ var InterestRateMode = /* @__PURE__ */ ((InterestRateMode2) => {
28
+ InterestRateMode2["Variable"] = "variable";
29
+ InterestRateMode2["Stable"] = "stable";
30
+ return InterestRateMode2;
31
+ })(InterestRateMode || {});
32
+
33
+ // src/error.ts
34
+ var DefiError = class _DefiError extends Error {
35
+ code;
36
+ constructor(code, message) {
37
+ super(message);
38
+ this.name = "DefiError";
39
+ this.code = code;
40
+ }
41
+ static protocolNotFound(name) {
42
+ return new _DefiError("PROTOCOL_NOT_FOUND", `Protocol not found: ${name}`);
43
+ }
44
+ static tokenNotFound(name) {
45
+ return new _DefiError("TOKEN_NOT_FOUND", `Token not found: ${name}`);
46
+ }
47
+ static chainNotFound(name) {
48
+ return new _DefiError("CHAIN_NOT_FOUND", `Chain not found: ${name}`);
49
+ }
50
+ static insufficientBalance(needed, available) {
51
+ return new _DefiError(
52
+ "INSUFFICIENT_BALANCE",
53
+ `Insufficient balance: need ${needed}, have ${available}`
54
+ );
55
+ }
56
+ static insufficientAllowance(spender) {
57
+ return new _DefiError(
58
+ "INSUFFICIENT_ALLOWANCE",
59
+ `Insufficient allowance for spender ${spender}`
60
+ );
61
+ }
62
+ static slippageExceeded(expected, actual) {
63
+ return new _DefiError(
64
+ "SLIPPAGE_EXCEEDED",
65
+ `Slippage exceeded: expected ${expected}, got ${actual}`
66
+ );
67
+ }
68
+ static simulationFailed(reason) {
69
+ return new _DefiError(
70
+ "SIMULATION_FAILED",
71
+ `Transaction simulation failed: ${reason}`
72
+ );
73
+ }
74
+ static abiError(reason) {
75
+ return new _DefiError("ABI_ERROR", `ABI encoding error: ${reason}`);
76
+ }
77
+ static registryError(reason) {
78
+ return new _DefiError("REGISTRY_ERROR", `Registry error: ${reason}`);
79
+ }
80
+ static rpcError(reason) {
81
+ return new _DefiError("RPC_ERROR", `RPC error: ${reason}`);
82
+ }
83
+ static providerError(reason) {
84
+ return new _DefiError("PROVIDER_ERROR", `Provider error: ${reason}`);
85
+ }
86
+ static contractError(reason) {
87
+ return new _DefiError("CONTRACT_ERROR", `Contract error: ${reason}`);
88
+ }
89
+ static invalidParam(reason) {
90
+ return new _DefiError("INVALID_PARAM", `Invalid parameter: ${reason}`);
91
+ }
92
+ static unsupported(operation) {
93
+ return new _DefiError(
94
+ "UNSUPPORTED",
95
+ `Unsupported operation: ${operation}`
96
+ );
97
+ }
98
+ static internal(reason) {
99
+ return new _DefiError("INTERNAL", `Internal error: ${reason}`);
100
+ }
101
+ toJSON() {
102
+ return { error: this.message };
103
+ }
104
+ };
105
+
106
+ // src/json.ts
107
+ function jsonReplacer(_key, value) {
108
+ if (typeof value === "bigint") {
109
+ return "0x" + value.toString(16);
110
+ }
111
+ return value;
112
+ }
113
+ function jsonReplacerDecimal(_key, value) {
114
+ if (typeof value === "bigint") {
115
+ return value.toString();
116
+ }
117
+ return value;
118
+ }
119
+ function jsonStringify(data, pretty = true) {
120
+ return pretty ? JSON.stringify(data, jsonReplacerDecimal, 2) : JSON.stringify(data, jsonReplacerDecimal);
121
+ }
122
+ function parseBigInt(value) {
123
+ if (value.startsWith("0x") || value.startsWith("0X")) {
124
+ return BigInt(value);
125
+ }
126
+ return BigInt(value);
127
+ }
128
+
129
+ // src/erc20.ts
130
+ import { encodeFunctionData, parseAbi } from "viem";
131
+ var erc20Abi = parseAbi([
132
+ "function name() view returns (string)",
133
+ "function symbol() view returns (string)",
134
+ "function decimals() view returns (uint8)",
135
+ "function totalSupply() view returns (uint256)",
136
+ "function balanceOf(address account) view returns (uint256)",
137
+ "function transfer(address to, uint256 amount) returns (bool)",
138
+ "function allowance(address owner, address spender) view returns (uint256)",
139
+ "function approve(address spender, uint256 amount) returns (bool)",
140
+ "function transferFrom(address from, address to, uint256 amount) returns (bool)"
141
+ ]);
142
+ function buildApprove(token, spender, amount) {
143
+ const data = encodeFunctionData({
144
+ abi: erc20Abi,
145
+ functionName: "approve",
146
+ args: [spender, amount]
147
+ });
148
+ return {
149
+ description: `Approve ${spender} to spend ${amount} of token ${token}`,
150
+ to: token,
151
+ data,
152
+ value: 0n,
153
+ gas_estimate: 6e4
154
+ };
155
+ }
156
+ function buildTransfer(token, to, amount) {
157
+ const data = encodeFunctionData({
158
+ abi: erc20Abi,
159
+ functionName: "transfer",
160
+ args: [to, amount]
161
+ });
162
+ return {
163
+ description: `Transfer ${amount} of token ${token} to ${to}`,
164
+ to: token,
165
+ data,
166
+ value: 0n,
167
+ gas_estimate: 65e3
168
+ };
169
+ }
170
+
171
+ // src/provider.ts
172
+ import { createPublicClient, http } from "viem";
173
+ var providerCache = /* @__PURE__ */ new Map();
174
+ function getProvider(rpcUrl) {
175
+ const cached = providerCache.get(rpcUrl);
176
+ if (cached) return cached;
177
+ const client = createPublicClient({ transport: http(rpcUrl) });
178
+ providerCache.set(rpcUrl, client);
179
+ return client;
180
+ }
181
+ function clearProviderCache() {
182
+ providerCache.clear();
183
+ }
184
+
185
+ // src/multicall.ts
186
+ import { encodeFunctionData as encodeFunctionData2, decodeFunctionResult, parseAbi as parseAbi2 } from "viem";
187
+ var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
188
+ var multicall3Abi = parseAbi2([
189
+ "struct Call3 { address target; bool allowFailure; bytes callData; }",
190
+ "struct Result { bool success; bytes returnData; }",
191
+ "function aggregate3(Call3[] calls) returns (Result[] returnData)"
192
+ ]);
193
+ function buildMulticall(calls) {
194
+ const mcCalls = calls.map(([target, callData]) => ({
195
+ target,
196
+ allowFailure: true,
197
+ callData
198
+ }));
199
+ const data = encodeFunctionData2({
200
+ abi: multicall3Abi,
201
+ functionName: "aggregate3",
202
+ args: [mcCalls]
203
+ });
204
+ return {
205
+ description: `Multicall3 batch (${calls.length} calls)`,
206
+ to: MULTICALL3_ADDRESS,
207
+ data,
208
+ value: 0n
209
+ };
210
+ }
211
+ async function multicallRead(rpcUrl, calls) {
212
+ const client = getProvider(rpcUrl);
213
+ const mcCalls = calls.map(([target, callData]) => ({
214
+ target,
215
+ allowFailure: true,
216
+ callData
217
+ }));
218
+ const result = await client.call({
219
+ to: MULTICALL3_ADDRESS,
220
+ data: encodeFunctionData2({
221
+ abi: multicall3Abi,
222
+ functionName: "aggregate3",
223
+ args: [mcCalls]
224
+ })
225
+ });
226
+ if (!result.data) return calls.map(() => null);
227
+ const decoded = decodeFunctionResult({
228
+ abi: multicall3Abi,
229
+ functionName: "aggregate3",
230
+ data: result.data
231
+ });
232
+ return decoded.map((r) => r.success ? r.returnData : null);
233
+ }
234
+ function decodeU256(data) {
235
+ if (!data || data.length < 66) return 0n;
236
+ return BigInt(data.slice(0, 66));
237
+ }
238
+ function decodeU128(data) {
239
+ if (!data || data.length < 66) return 0n;
240
+ const val = BigInt(data.slice(0, 66));
241
+ return val & (1n << 128n) - 1n;
242
+ }
243
+
244
+ // src/registry/chain.ts
245
+ var ChainConfig = class {
246
+ name;
247
+ chain_id;
248
+ rpc_url;
249
+ explorer_url;
250
+ native_token;
251
+ wrapped_native;
252
+ multicall3;
253
+ effectiveRpcUrl() {
254
+ const chainEnv = this.name.toUpperCase().replace(/ /g, "_") + "_RPC_URL";
255
+ return process.env[chainEnv] ?? process.env["HYPEREVM_RPC_URL"] ?? this.rpc_url;
256
+ }
257
+ };
258
+
259
+ // src/registry/protocol.ts
260
+ var ProtocolCategory = /* @__PURE__ */ ((ProtocolCategory2) => {
261
+ ProtocolCategory2["Dex"] = "dex";
262
+ ProtocolCategory2["Lending"] = "lending";
263
+ ProtocolCategory2["Cdp"] = "cdp";
264
+ ProtocolCategory2["Bridge"] = "bridge";
265
+ ProtocolCategory2["LiquidStaking"] = "liquid_staking";
266
+ ProtocolCategory2["YieldSource"] = "yield_source";
267
+ ProtocolCategory2["YieldAggregator"] = "yield_aggregator";
268
+ ProtocolCategory2["Vault"] = "vault";
269
+ ProtocolCategory2["Derivatives"] = "derivatives";
270
+ ProtocolCategory2["Options"] = "options";
271
+ ProtocolCategory2["LiquidityManager"] = "liquidity_manager";
272
+ ProtocolCategory2["Nft"] = "nft";
273
+ ProtocolCategory2["Other"] = "other";
274
+ return ProtocolCategory2;
275
+ })(ProtocolCategory || {});
276
+ function protocolCategoryLabel(category) {
277
+ switch (category) {
278
+ case "dex" /* Dex */:
279
+ return "DEX";
280
+ case "lending" /* Lending */:
281
+ return "Lending";
282
+ case "cdp" /* Cdp */:
283
+ return "CDP";
284
+ case "bridge" /* Bridge */:
285
+ return "Bridge";
286
+ case "liquid_staking" /* LiquidStaking */:
287
+ return "Liquid Staking";
288
+ case "yield_source" /* YieldSource */:
289
+ return "Yield Source";
290
+ case "yield_aggregator" /* YieldAggregator */:
291
+ return "Yield Aggregator";
292
+ case "vault" /* Vault */:
293
+ return "Vault";
294
+ case "derivatives" /* Derivatives */:
295
+ return "Derivatives";
296
+ case "options" /* Options */:
297
+ return "Options";
298
+ case "liquidity_manager" /* LiquidityManager */:
299
+ return "Liquidity Manager";
300
+ case "nft" /* Nft */:
301
+ return "NFT";
302
+ case "other" /* Other */:
303
+ return "Other";
304
+ }
305
+ }
306
+
307
+ // src/registry/registry.ts
308
+ import { readFileSync, readdirSync } from "fs";
309
+ import { resolve } from "path";
310
+ import { fileURLToPath } from "url";
311
+ import { parse } from "smol-toml";
312
+ import { existsSync } from "fs";
313
+ var __dirname = fileURLToPath(new URL(".", import.meta.url));
314
+ function findConfigDir() {
315
+ const candidates = [
316
+ resolve(__dirname, "../../../config"),
317
+ // from dist/registry/ (monorepo build)
318
+ resolve(__dirname, "../../../../config"),
319
+ // from src/registry/ (vitest)
320
+ resolve(__dirname, "../config"),
321
+ // from dist/ (npm bundle — config at package root)
322
+ resolve(__dirname, "../../config")
323
+ // from dist/subdir (npm bundle variant)
324
+ ];
325
+ for (const dir of candidates) {
326
+ if (existsSync(resolve(dir, "chains.toml"))) return dir;
327
+ }
328
+ throw new Error(`Config directory not found. Searched: ${candidates.join(", ")}`);
329
+ }
330
+ var CONFIG_DIR = findConfigDir();
331
+ function readToml(relPath) {
332
+ return readFileSync(resolve(CONFIG_DIR, relPath), "utf-8");
333
+ }
334
+ var Registry = class _Registry {
335
+ chains;
336
+ tokens;
337
+ protocols;
338
+ constructor(chains, tokens, protocols) {
339
+ this.chains = chains;
340
+ this.tokens = tokens;
341
+ this.protocols = protocols;
342
+ }
343
+ static loadEmbedded() {
344
+ const chains = _Registry.loadChains();
345
+ const tokens = _Registry.loadTokens();
346
+ const protocols = _Registry.loadProtocols();
347
+ return new _Registry(chains, tokens, protocols);
348
+ }
349
+ static loadChains() {
350
+ const raw = parse(readToml("chains.toml"));
351
+ const map = /* @__PURE__ */ new Map();
352
+ for (const [key, data] of Object.entries(raw.chain)) {
353
+ const cfg = Object.assign(new ChainConfig(), data);
354
+ map.set(key, cfg);
355
+ }
356
+ return map;
357
+ }
358
+ static loadTokens() {
359
+ const map = /* @__PURE__ */ new Map();
360
+ const tokensDir = resolve(CONFIG_DIR, "tokens");
361
+ try {
362
+ const files = readdirSync(tokensDir).filter((f) => f.endsWith(".toml"));
363
+ for (const file of files) {
364
+ const chain = file.replace(".toml", "");
365
+ try {
366
+ const raw = parse(readToml(`tokens/${file}`));
367
+ map.set(chain, raw.token);
368
+ } catch {
369
+ }
370
+ }
371
+ } catch {
372
+ }
373
+ return map;
374
+ }
375
+ static loadProtocols() {
376
+ const protocols = [];
377
+ const protocolsDir = resolve(CONFIG_DIR, "protocols");
378
+ const categories = ["dex", "lending", "cdp", "vault", "liquid_staking", "yield_aggregator", "yield_source", "derivatives", "options", "nft", "bridge"];
379
+ for (const category of categories) {
380
+ const catDir = resolve(protocolsDir, category);
381
+ try {
382
+ if (!existsSync(catDir)) continue;
383
+ const files = readdirSync(catDir).filter((f) => f.endsWith(".toml"));
384
+ for (const file of files) {
385
+ try {
386
+ const raw = parse(readToml(`protocols/${category}/${file}`));
387
+ protocols.push(raw.protocol);
388
+ } catch {
389
+ }
390
+ }
391
+ } catch {
392
+ }
393
+ }
394
+ return protocols;
395
+ }
396
+ getChain(name) {
397
+ const chain = this.chains.get(name);
398
+ if (!chain) throw new Error(`Chain not found: ${name}`);
399
+ return chain;
400
+ }
401
+ getProtocol(name) {
402
+ const protocol = this.protocols.find(
403
+ (p) => p.name.toLowerCase() === name.toLowerCase() || p.slug.toLowerCase() === name.toLowerCase()
404
+ );
405
+ if (!protocol) throw new Error(`Protocol not found: ${name}`);
406
+ return protocol;
407
+ }
408
+ getProtocolsByCategory(category) {
409
+ return this.protocols.filter((p) => p.category === category);
410
+ }
411
+ getProtocolsForChain(chain, includeUnverified = false) {
412
+ return this.protocols.filter(
413
+ (p) => p.chain.toLowerCase() === chain.toLowerCase() && (includeUnverified || p.verified !== false)
414
+ );
415
+ }
416
+ resolveToken(chain, symbol) {
417
+ const tokens = this.tokens.get(chain);
418
+ if (!tokens) throw new Error(`Chain not found: ${chain}`);
419
+ const token = tokens.find(
420
+ (t) => t.symbol.toLowerCase() === symbol.toLowerCase()
421
+ );
422
+ if (!token) throw new Error(`Token not found: ${symbol}`);
423
+ return token;
424
+ }
425
+ /**
426
+ * Resolve a pool by name (e.g. "WHYPE/USDC") from a protocol's pool list.
427
+ * Returns the pool info or throws if not found.
428
+ */
429
+ resolvePool(protocolSlug, poolName) {
430
+ const protocol = this.getProtocol(protocolSlug);
431
+ if (!protocol.pools || protocol.pools.length === 0) {
432
+ throw new Error(`Protocol ${protocol.name} has no pools configured`);
433
+ }
434
+ const pool = protocol.pools.find(
435
+ (p) => p.name.toLowerCase() === poolName.toLowerCase()
436
+ );
437
+ if (!pool) {
438
+ const available = protocol.pools.map((p) => p.name).join(", ");
439
+ throw new Error(`Pool '${poolName}' not found in ${protocol.name}. Available: ${available}`);
440
+ }
441
+ return pool;
442
+ }
443
+ };
444
+ export {
445
+ ChainConfig,
446
+ DefiError,
447
+ InterestRateMode,
448
+ MULTICALL3_ADDRESS,
449
+ ProtocolCategory,
450
+ Registry,
451
+ TxStatus,
452
+ applyMinSlippage,
453
+ buildApprove,
454
+ buildMulticall,
455
+ buildTransfer,
456
+ clearProviderCache,
457
+ decodeU128,
458
+ decodeU256,
459
+ defaultSwapSlippage,
460
+ erc20Abi,
461
+ formatHuman,
462
+ getProvider,
463
+ jsonReplacer,
464
+ jsonReplacerDecimal,
465
+ jsonStringify,
466
+ multicallRead,
467
+ newSlippage,
468
+ parseBigInt,
469
+ protocolCategoryLabel
470
+ };
471
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/error.ts","../src/json.ts","../src/erc20.ts","../src/provider.ts","../src/multicall.ts","../src/registry/chain.ts","../src/registry/protocol.ts","../src/registry/registry.ts"],"sourcesContent":["import type { Address, Hex } from \"viem\";\n\n// === Transaction Types ===\n\n/** A built DeFi transaction ready for simulation or broadcast */\nexport interface DeFiTx {\n description: string;\n to: Address;\n data: Hex;\n value: bigint;\n gas_estimate?: number;\n /** ERC20 approvals to check and send before broadcasting this tx */\n approvals?: Array<{\n token: Address;\n spender: Address;\n amount: bigint;\n }>;\n /** Pre-transactions to execute before the main tx (e.g. farming approval) */\n pre_txs?: DeFiTx[];\n}\n\n/** Result of executing or simulating a transaction */\nexport interface ActionResult {\n tx_hash?: string;\n status: TxStatus;\n gas_used?: number;\n description: string;\n details: Record<string, unknown>;\n}\n\n/** Transaction status (serde: snake_case) */\nexport enum TxStatus {\n DryRun = \"dry_run\",\n Simulated = \"simulated\",\n SimulationFailed = \"simulation_failed\",\n NeedsApproval = \"needs_approval\",\n Pending = \"pending\",\n Confirmed = \"confirmed\",\n Failed = \"failed\",\n}\n\n// === Token Types ===\n\n/** Token amount with decimals-aware formatting */\nexport interface TokenAmount {\n token: Address;\n symbol: string;\n amount: bigint;\n decimals: number;\n}\n\nexport function formatHuman(t: TokenAmount): string {\n const divisor = 10n ** BigInt(t.decimals);\n const whole = t.amount / divisor;\n const frac = t.amount % divisor;\n return `${whole}.${frac.toString().padStart(t.decimals, \"0\")} ${t.symbol}`;\n}\n\n/** Slippage tolerance in basis points */\nexport interface Slippage {\n bps: number;\n}\n\nexport function newSlippage(bps: number): Slippage {\n return { bps };\n}\n\nexport function defaultSwapSlippage(): Slippage {\n return { bps: 50 };\n}\n\nexport function applyMinSlippage(slippage: Slippage, amount: bigint): bigint {\n return (amount * BigInt(10000 - slippage.bps)) / 10000n;\n}\n\n// === Oracle / Price Types ===\n\nexport interface PriceData {\n source: string;\n source_type: string;\n asset: Address;\n price_usd: bigint;\n price_f64: number;\n block_number?: number;\n timestamp?: number;\n}\n\n// === DEX Types ===\n\nexport interface SwapParams {\n protocol: string;\n token_in: Address;\n token_out: Address;\n amount_in: bigint;\n slippage: Slippage;\n recipient: Address;\n deadline?: number;\n}\n\nexport interface QuoteParams {\n protocol: string;\n token_in: Address;\n token_out: Address;\n amount_in: bigint;\n}\n\nexport interface QuoteResult {\n protocol: string;\n amount_out: bigint;\n price_impact_bps?: number;\n fee_bps?: number;\n route: string[];\n}\n\nexport interface AddLiquidityParams {\n protocol: string;\n token_a: Address;\n token_b: Address;\n amount_a: bigint;\n amount_b: bigint;\n recipient: Address;\n /** Optional lower tick for concentrated LP (defaults to full range) */\n tick_lower?: number;\n /** Optional upper tick for concentrated LP (defaults to full range) */\n tick_upper?: number;\n /** ±N% concentrated range around current price (e.g. 2 for ±2%) */\n range_pct?: number;\n /** Optional pool address for tick detection / single-side LP */\n pool?: Address;\n}\n\nexport interface RemoveLiquidityParams {\n protocol: string;\n token_a: Address;\n token_b: Address;\n liquidity: bigint;\n recipient: Address;\n}\n\n// === Lending Types ===\n\nexport interface SupplyParams {\n protocol: string;\n asset: Address;\n amount: bigint;\n on_behalf_of: Address;\n}\n\nexport interface BorrowParams {\n protocol: string;\n asset: Address;\n amount: bigint;\n interest_rate_mode: InterestRateMode;\n on_behalf_of: Address;\n}\n\n/** Interest rate mode (serde: snake_case) */\nexport enum InterestRateMode {\n Variable = \"variable\",\n Stable = \"stable\",\n}\n\nexport interface RepayParams {\n protocol: string;\n asset: Address;\n amount: bigint;\n interest_rate_mode: InterestRateMode;\n on_behalf_of: Address;\n}\n\nexport interface WithdrawParams {\n protocol: string;\n asset: Address;\n amount: bigint;\n to: Address;\n}\n\nexport interface LendingRates {\n protocol: string;\n asset: Address;\n supply_apy: number;\n borrow_variable_apy: number;\n borrow_stable_apy?: number;\n utilization: number;\n total_supply: bigint;\n total_borrow: bigint;\n /** Reward token addresses for supply-side incentives */\n supply_reward_tokens?: string[];\n /** Reward token addresses for borrow-side incentives */\n borrow_reward_tokens?: string[];\n /** Emissions per second per supply reward token (raw uint256 as string) */\n supply_emissions_per_second?: string[];\n /** Emissions per second per borrow reward token (raw uint256 as string) */\n borrow_emissions_per_second?: string[];\n /** Supply-side incentive APY (%) from reward token emissions */\n supply_incentive_apy?: number;\n /** Borrow-side incentive APY (%) from reward token emissions (negative = subsidized) */\n borrow_incentive_apy?: number;\n}\n\nexport interface UserPosition {\n protocol: string;\n user: Address;\n supplies: PositionAsset[];\n borrows: PositionAsset[];\n health_factor?: number;\n net_apy?: number;\n}\n\nexport interface PositionAsset {\n asset: Address;\n symbol: string;\n amount: bigint;\n value_usd?: number;\n}\n\n// === CDP Types ===\n\nexport interface OpenCdpParams {\n protocol: string;\n collateral: Address;\n collateral_amount: bigint;\n debt_amount: bigint;\n recipient: Address;\n}\n\nexport interface AdjustCdpParams {\n protocol: string;\n cdp_id: bigint;\n collateral_delta?: bigint;\n debt_delta?: bigint;\n add_collateral: boolean;\n add_debt: boolean;\n}\n\nexport interface CloseCdpParams {\n protocol: string;\n cdp_id: bigint;\n}\n\nexport interface CdpInfo {\n protocol: string;\n cdp_id: bigint;\n collateral: TokenAmount;\n debt: TokenAmount;\n collateral_ratio: number;\n liquidation_price?: number;\n}\n\n// === Liquid Staking Types ===\n\nexport interface StakeParams {\n protocol: string;\n amount: bigint;\n recipient: Address;\n}\n\nexport interface UnstakeParams {\n protocol: string;\n amount: bigint;\n recipient: Address;\n}\n\nexport interface StakingInfo {\n protocol: string;\n staked_token: Address;\n liquid_token: Address;\n exchange_rate: number;\n apy?: number;\n total_staked: bigint;\n}\n\n// === Vault Types (ERC-4626) ===\n\nexport interface VaultInfo {\n protocol: string;\n vault_address: Address;\n asset: Address;\n total_assets: bigint;\n total_supply: bigint;\n apy?: number;\n}\n\n// === Derivatives Types ===\n\nexport interface DerivativesPositionParams {\n protocol: string;\n market: string;\n size: bigint;\n collateral: bigint;\n is_long: boolean;\n}\n\n// === Options Types ===\n\nexport interface OptionParams {\n protocol: string;\n underlying: Address;\n strike_price: bigint;\n expiry: number;\n is_call: boolean;\n amount: bigint;\n}\n\n// === ve(3,3) Types ===\n\n/** A pool that has an active emission gauge */\nexport interface GaugedPool {\n pool: Address;\n gauge: Address;\n token0: string; // symbol\n token1: string; // symbol\n token0Addr?: Address;\n token1Addr?: Address;\n type: \"V2\" | \"CL\";\n tickSpacing?: number; // for CL pools\n stable?: boolean; // for V2 pools\n /** Reward rate in wei per second (from gauge.rewardRate or rewardData) */\n rewardRate?: bigint;\n /** Total LP staked in gauge (wei) */\n totalStaked?: bigint;\n /** Reward token address */\n rewardToken?: Address;\n /** Calculated emission APR (%) — set by caller if prices available */\n aprPercent?: number;\n /** Pool TVL in USD — set by caller if prices available */\n poolTvlUsd?: number;\n}\n\nexport interface RewardInfo {\n token: Address;\n symbol: string;\n amount: bigint;\n value_usd?: number;\n}\n\nexport interface GaugeInfo {\n gauge: Address;\n pool: Address;\n total_staked: bigint;\n reward_rate: bigint;\n rewards: RewardInfo[];\n}\n\nexport interface VeNftInfo {\n token_id: bigint;\n amount: bigint;\n unlock_time: number;\n voting_power: bigint;\n}\n\n// === Yield Types ===\n\nexport interface YieldInfo {\n protocol: string;\n pool: string;\n apy: number;\n tvl: bigint;\n tokens: Address[];\n}\n\n// === Portfolio Tracker Types ===\nexport interface PortfolioSnapshot {\n timestamp: number;\n chain: string;\n wallet: string;\n tokens: TokenBalance[];\n defi_positions: DefiPosition[];\n total_value_usd: number;\n}\n\nexport interface TokenBalance {\n token: string;\n symbol: string;\n balance: bigint;\n value_usd: number;\n price_usd: number;\n}\n\nexport interface DefiPosition {\n protocol: string;\n type: \"lending_supply\" | \"lending_borrow\" | \"lp\" | \"staking\" | \"vault\";\n asset: string;\n amount: bigint;\n value_usd: number;\n}\n\nexport interface PortfolioPnL {\n period: string;\n start_value_usd: number;\n end_value_usd: number;\n pnl_usd: number;\n pnl_pct: number;\n token_changes: TokenChange[];\n}\n\nexport interface TokenChange {\n symbol: string;\n balance_change: bigint;\n value_change_usd: number;\n}\n","import type { Address } from \"viem\";\n\nexport type DefiErrorCode =\n | \"PROTOCOL_NOT_FOUND\"\n | \"TOKEN_NOT_FOUND\"\n | \"CHAIN_NOT_FOUND\"\n | \"INSUFFICIENT_BALANCE\"\n | \"INSUFFICIENT_ALLOWANCE\"\n | \"SLIPPAGE_EXCEEDED\"\n | \"SIMULATION_FAILED\"\n | \"ABI_ERROR\"\n | \"REGISTRY_ERROR\"\n | \"RPC_ERROR\"\n | \"PROVIDER_ERROR\"\n | \"CONTRACT_ERROR\"\n | \"INVALID_PARAM\"\n | \"UNSUPPORTED\"\n | \"TX_FAILED\"\n | \"INTERNAL\";\n\nexport class DefiError extends Error {\n readonly code: DefiErrorCode;\n\n constructor(code: DefiErrorCode, message: string) {\n super(message);\n this.name = \"DefiError\";\n this.code = code;\n }\n\n static protocolNotFound(name: string): DefiError {\n return new DefiError(\"PROTOCOL_NOT_FOUND\", `Protocol not found: ${name}`);\n }\n\n static tokenNotFound(name: string): DefiError {\n return new DefiError(\"TOKEN_NOT_FOUND\", `Token not found: ${name}`);\n }\n\n static chainNotFound(name: string): DefiError {\n return new DefiError(\"CHAIN_NOT_FOUND\", `Chain not found: ${name}`);\n }\n\n static insufficientBalance(needed: string, available: string): DefiError {\n return new DefiError(\n \"INSUFFICIENT_BALANCE\",\n `Insufficient balance: need ${needed}, have ${available}`,\n );\n }\n\n static insufficientAllowance(spender: Address): DefiError {\n return new DefiError(\n \"INSUFFICIENT_ALLOWANCE\",\n `Insufficient allowance for spender ${spender}`,\n );\n }\n\n static slippageExceeded(expected: string, actual: string): DefiError {\n return new DefiError(\n \"SLIPPAGE_EXCEEDED\",\n `Slippage exceeded: expected ${expected}, got ${actual}`,\n );\n }\n\n static simulationFailed(reason: string): DefiError {\n return new DefiError(\n \"SIMULATION_FAILED\",\n `Transaction simulation failed: ${reason}`,\n );\n }\n\n static abiError(reason: string): DefiError {\n return new DefiError(\"ABI_ERROR\", `ABI encoding error: ${reason}`);\n }\n\n static registryError(reason: string): DefiError {\n return new DefiError(\"REGISTRY_ERROR\", `Registry error: ${reason}`);\n }\n\n static rpcError(reason: string): DefiError {\n return new DefiError(\"RPC_ERROR\", `RPC error: ${reason}`);\n }\n\n static providerError(reason: string): DefiError {\n return new DefiError(\"PROVIDER_ERROR\", `Provider error: ${reason}`);\n }\n\n static contractError(reason: string): DefiError {\n return new DefiError(\"CONTRACT_ERROR\", `Contract error: ${reason}`);\n }\n\n static invalidParam(reason: string): DefiError {\n return new DefiError(\"INVALID_PARAM\", `Invalid parameter: ${reason}`);\n }\n\n static unsupported(operation: string): DefiError {\n return new DefiError(\n \"UNSUPPORTED\",\n `Unsupported operation: ${operation}`,\n );\n }\n\n static internal(reason: string): DefiError {\n return new DefiError(\"INTERNAL\", `Internal error: ${reason}`);\n }\n\n toJSON() {\n return { error: this.message };\n }\n}\n\nexport type Result<T> = T;\n","/**\n * BigInt JSON serialization utilities.\n *\n * Rust's alloy U256 (backed by ruint) serializes to JSON as 0x-prefixed\n * lowercase hex strings (e.g., \"0x75bcd15\"). We must match this exactly\n * for behavioral parity.\n */\n\n/** JSON replacer for Rust parity — bigint becomes 0x-hex string */\nexport function jsonReplacer(_key: string, value: unknown): unknown {\n if (typeof value === \"bigint\") {\n return \"0x\" + value.toString(16);\n }\n return value;\n}\n\n/** JSON replacer for SDK consumers — bigint becomes decimal string */\nexport function jsonReplacerDecimal(_key: string, value: unknown): unknown {\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n return value;\n}\n\n/** Stringify with decimal bigint handling */\nexport function jsonStringify(data: unknown, pretty = true): string {\n return pretty\n ? JSON.stringify(data, jsonReplacerDecimal, 2)\n : JSON.stringify(data, jsonReplacerDecimal);\n}\n\n/** Parse a 0x-hex or decimal string to bigint */\nexport function parseBigInt(value: string): bigint {\n if (value.startsWith(\"0x\") || value.startsWith(\"0X\")) {\n return BigInt(value);\n }\n return BigInt(value);\n}\n","import type { Address, Hex } from \"viem\";\nimport { encodeFunctionData, parseAbi } from \"viem\";\nimport type { DeFiTx } from \"./types.js\";\n\nconst erc20Abi = parseAbi([\n \"function name() view returns (string)\",\n \"function symbol() view returns (string)\",\n \"function decimals() view returns (uint8)\",\n \"function totalSupply() view returns (uint256)\",\n \"function balanceOf(address account) view returns (uint256)\",\n \"function transfer(address to, uint256 amount) returns (bool)\",\n \"function allowance(address owner, address spender) view returns (uint256)\",\n \"function approve(address spender, uint256 amount) returns (bool)\",\n \"function transferFrom(address from, address to, uint256 amount) returns (bool)\",\n]);\n\nexport { erc20Abi };\n\nexport function buildApprove(\n token: Address,\n spender: Address,\n amount: bigint,\n): DeFiTx {\n const data = encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n });\n return {\n description: `Approve ${spender} to spend ${amount} of token ${token}`,\n to: token,\n data,\n value: 0n,\n gas_estimate: 60_000,\n };\n}\n\nexport function buildTransfer(\n token: Address,\n to: Address,\n amount: bigint,\n): DeFiTx {\n const data = encodeFunctionData({\n abi: erc20Abi,\n functionName: \"transfer\",\n args: [to, amount],\n });\n return {\n description: `Transfer ${amount} of token ${token} to ${to}`,\n to: token,\n data,\n value: 0n,\n gas_estimate: 65_000,\n };\n}\n","import { createPublicClient, http, type PublicClient } from \"viem\";\n\nconst providerCache = new Map<string, PublicClient>();\n\nexport function getProvider(rpcUrl: string): PublicClient {\n const cached = providerCache.get(rpcUrl);\n if (cached) return cached;\n\n const client = createPublicClient({ transport: http(rpcUrl) });\n providerCache.set(rpcUrl, client);\n return client;\n}\n\nexport function clearProviderCache(): void {\n providerCache.clear();\n}\n","import type { Address, Hex } from \"viem\";\nimport { encodeFunctionData, decodeFunctionResult, parseAbi } from \"viem\";\nimport type { DeFiTx } from \"./types.js\";\nimport { getProvider } from \"./provider.js\";\n\nexport const MULTICALL3_ADDRESS: Address =\n \"0xcA11bde05977b3631167028862bE2a173976CA11\";\n\nconst multicall3Abi = parseAbi([\n \"struct Call3 { address target; bool allowFailure; bytes callData; }\",\n \"struct Result { bool success; bytes returnData; }\",\n \"function aggregate3(Call3[] calls) returns (Result[] returnData)\",\n]);\n\nexport function buildMulticall(calls: Array<[Address, Hex]>): DeFiTx {\n const mcCalls = calls.map(([target, callData]) => ({\n target,\n allowFailure: true,\n callData,\n }));\n\n const data = encodeFunctionData({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n args: [mcCalls],\n });\n\n return {\n description: `Multicall3 batch (${calls.length} calls)`,\n to: MULTICALL3_ADDRESS,\n data,\n value: 0n,\n };\n}\n\nexport async function multicallRead(\n rpcUrl: string,\n calls: Array<[Address, Hex]>,\n): Promise<(Hex | null)[]> {\n const client = getProvider(rpcUrl);\n\n const mcCalls = calls.map(([target, callData]) => ({\n target,\n allowFailure: true,\n callData,\n }));\n\n const result = await client.call({\n to: MULTICALL3_ADDRESS,\n data: encodeFunctionData({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n args: [mcCalls],\n }),\n });\n\n if (!result.data) return calls.map(() => null);\n\n const decoded = decodeFunctionResult({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n data: result.data,\n }) as Array<{ success: boolean; returnData: Hex }>;\n\n return decoded.map((r) => (r.success ? r.returnData : null));\n}\n\nexport function decodeU256(data: Hex | null): bigint {\n if (!data || data.length < 66) return 0n;\n return BigInt(data.slice(0, 66));\n}\n\nexport function decodeU128(data: Hex | null): bigint {\n if (!data || data.length < 66) return 0n;\n const val = BigInt(data.slice(0, 66));\n return val & ((1n << 128n) - 1n);\n}\n","export class ChainConfig {\n name!: string;\n chain_id!: number;\n rpc_url!: string;\n explorer_url?: string;\n native_token!: string;\n wrapped_native?: string;\n multicall3?: string;\n\n effectiveRpcUrl(): string {\n const chainEnv = this.name.toUpperCase().replace(/ /g, \"_\") + \"_RPC_URL\";\n return (\n process.env[chainEnv] ??\n process.env[\"HYPEREVM_RPC_URL\"] ??\n this.rpc_url\n );\n }\n}\n","import type { Address } from \"viem\";\n\nexport enum ProtocolCategory {\n Dex = \"dex\",\n Lending = \"lending\",\n Cdp = \"cdp\",\n Bridge = \"bridge\",\n LiquidStaking = \"liquid_staking\",\n YieldSource = \"yield_source\",\n YieldAggregator = \"yield_aggregator\",\n Vault = \"vault\",\n Derivatives = \"derivatives\",\n Options = \"options\",\n LiquidityManager = \"liquidity_manager\",\n Nft = \"nft\",\n Other = \"other\",\n}\n\nexport function protocolCategoryLabel(category: ProtocolCategory): string {\n switch (category) {\n case ProtocolCategory.Dex:\n return \"DEX\";\n case ProtocolCategory.Lending:\n return \"Lending\";\n case ProtocolCategory.Cdp:\n return \"CDP\";\n case ProtocolCategory.Bridge:\n return \"Bridge\";\n case ProtocolCategory.LiquidStaking:\n return \"Liquid Staking\";\n case ProtocolCategory.YieldSource:\n return \"Yield Source\";\n case ProtocolCategory.YieldAggregator:\n return \"Yield Aggregator\";\n case ProtocolCategory.Vault:\n return \"Vault\";\n case ProtocolCategory.Derivatives:\n return \"Derivatives\";\n case ProtocolCategory.Options:\n return \"Options\";\n case ProtocolCategory.LiquidityManager:\n return \"Liquidity Manager\";\n case ProtocolCategory.Nft:\n return \"NFT\";\n case ProtocolCategory.Other:\n return \"Other\";\n }\n}\n\nexport interface PoolInfo {\n name: string;\n address: Address;\n token0: string;\n token1: string;\n tick_spacing?: number;\n gauge?: Address;\n stable?: boolean;\n}\n\nexport interface ProtocolEntry {\n name: string;\n slug: string;\n category: ProtocolCategory;\n interface: string;\n chain: string;\n native?: boolean;\n verified?: boolean;\n contracts?: Record<string, Address>;\n pools?: PoolInfo[];\n description?: string;\n}\n","import { readFileSync, readdirSync } from \"fs\";\nimport { resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { parse } from \"smol-toml\";\nimport { ChainConfig } from \"./chain.js\";\nimport type { TokenEntry } from \"./token.js\";\nimport { type ProtocolEntry, type PoolInfo, ProtocolCategory } from \"./protocol.js\";\n\nimport { existsSync } from \"fs\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n\n// Resolve config dir: works from src/ (vitest), dist/ (built), and npm bundle (npx)\nfunction findConfigDir(): string {\n const candidates = [\n resolve(__dirname, \"../../../config\"), // from dist/registry/ (monorepo build)\n resolve(__dirname, \"../../../../config\"), // from src/registry/ (vitest)\n resolve(__dirname, \"../config\"), // from dist/ (npm bundle — config at package root)\n resolve(__dirname, \"../../config\"), // from dist/subdir (npm bundle variant)\n ];\n for (const dir of candidates) {\n if (existsSync(resolve(dir, \"chains.toml\"))) return dir;\n }\n throw new Error(`Config directory not found. Searched: ${candidates.join(\", \")}`);\n}\n\nconst CONFIG_DIR = findConfigDir();\n\nfunction readToml(relPath: string): string {\n return readFileSync(resolve(CONFIG_DIR, relPath), \"utf-8\");\n}\n\ninterface ChainConfigWrapper {\n chain: Record<string, ChainConfig>;\n}\n\ninterface TokensWrapper {\n token: TokenEntry[];\n}\n\ninterface ProtocolWrapper {\n protocol: ProtocolEntry;\n}\n\nexport class Registry {\n chains: Map<string, ChainConfig>;\n tokens: Map<string, TokenEntry[]>;\n protocols: ProtocolEntry[];\n\n private constructor(\n chains: Map<string, ChainConfig>,\n tokens: Map<string, TokenEntry[]>,\n protocols: ProtocolEntry[],\n ) {\n this.chains = chains;\n this.tokens = tokens;\n this.protocols = protocols;\n }\n\n static loadEmbedded(): Registry {\n const chains = Registry.loadChains();\n const tokens = Registry.loadTokens();\n const protocols = Registry.loadProtocols();\n return new Registry(chains, tokens, protocols);\n }\n\n private static loadChains(): Map<string, ChainConfig> {\n const raw = parse(readToml(\"chains.toml\")) as unknown as ChainConfigWrapper;\n const map = new Map<string, ChainConfig>();\n for (const [key, data] of Object.entries(raw.chain)) {\n const cfg = Object.assign(new ChainConfig(), data);\n map.set(key, cfg);\n }\n return map;\n }\n\n private static loadTokens(): Map<string, TokenEntry[]> {\n // Dynamically discover all token files in config/tokens/\n const map = new Map<string, TokenEntry[]>();\n const tokensDir = resolve(CONFIG_DIR, \"tokens\");\n try {\n const files = readdirSync(tokensDir).filter(f => f.endsWith(\".toml\"));\n for (const file of files) {\n const chain = file.replace(\".toml\", \"\");\n try {\n const raw = parse(readToml(`tokens/${file}`)) as unknown as TokensWrapper;\n map.set(chain, raw.token);\n } catch { /* skip invalid token files */ }\n }\n } catch { /* tokens dir may not exist */ }\n return map;\n }\n\n private static loadProtocols(): ProtocolEntry[] {\n // Dynamically discover all protocol TOML files across all categories\n const protocols: ProtocolEntry[] = [];\n const protocolsDir = resolve(CONFIG_DIR, \"protocols\");\n const categories = [\"dex\", \"lending\", \"cdp\", \"vault\", \"liquid_staking\", \"yield_aggregator\", \"yield_source\", \"derivatives\", \"options\", \"nft\", \"bridge\"];\n\n for (const category of categories) {\n const catDir = resolve(protocolsDir, category);\n try {\n if (!existsSync(catDir)) continue;\n const files = readdirSync(catDir).filter(f => f.endsWith(\".toml\"));\n for (const file of files) {\n try {\n const raw = parse(readToml(`protocols/${category}/${file}`)) as unknown as ProtocolWrapper;\n protocols.push(raw.protocol);\n } catch { /* skip invalid protocol files */ }\n }\n } catch { /* category dir may not exist */ }\n }\n return protocols;\n }\n\n getChain(name: string): ChainConfig {\n const chain = this.chains.get(name);\n if (!chain) throw new Error(`Chain not found: ${name}`);\n return chain;\n }\n\n getProtocol(name: string): ProtocolEntry {\n const protocol = this.protocols.find(\n (p) =>\n p.name.toLowerCase() === name.toLowerCase() ||\n p.slug.toLowerCase() === name.toLowerCase(),\n );\n if (!protocol) throw new Error(`Protocol not found: ${name}`);\n return protocol;\n }\n\n getProtocolsByCategory(category: ProtocolCategory): ProtocolEntry[] {\n return this.protocols.filter((p) => p.category === category);\n }\n\n getProtocolsForChain(chain: string, includeUnverified = false): ProtocolEntry[] {\n return this.protocols.filter(\n (p) =>\n p.chain.toLowerCase() === chain.toLowerCase() &&\n (includeUnverified || p.verified !== false),\n );\n }\n\n resolveToken(chain: string, symbol: string): TokenEntry {\n const tokens = this.tokens.get(chain);\n if (!tokens) throw new Error(`Chain not found: ${chain}`);\n const token = tokens.find(\n (t) => t.symbol.toLowerCase() === symbol.toLowerCase(),\n );\n if (!token) throw new Error(`Token not found: ${symbol}`);\n return token;\n }\n\n /**\n * Resolve a pool by name (e.g. \"WHYPE/USDC\") from a protocol's pool list.\n * Returns the pool info or throws if not found.\n */\n resolvePool(protocolSlug: string, poolName: string): PoolInfo {\n const protocol = this.getProtocol(protocolSlug);\n if (!protocol.pools || protocol.pools.length === 0) {\n throw new Error(`Protocol ${protocol.name} has no pools configured`);\n }\n const pool = protocol.pools.find(\n (p) => p.name.toLowerCase() === poolName.toLowerCase(),\n );\n if (!pool) {\n const available = protocol.pools.map(p => p.name).join(\", \");\n throw new Error(`Pool '${poolName}' not found in ${protocol.name}. Available: ${available}`);\n }\n return pool;\n }\n}\n"],"mappings":"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","names":["TxStatus","InterestRateMode","encodeFunctionData","parseAbi","parseAbi","encodeFunctionData","ProtocolCategory"]}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@hypurrquant/defi-core",
3
+ "version": "0.5.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist/",
15
+ "config/"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "test": "vitest run",
20
+ "lint": "tsc --noEmit",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "dependencies": {
24
+ "smol-toml": "^1.3.0",
25
+ "viem": "^2.23.0",
26
+ "zod": "^3.24.0"
27
+ }
28
+ }