@elmntl/jlpd-sdk 0.1.11 → 0.13.4

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 (115) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +185 -404
  3. package/dist/common/ata.d.ts +26 -0
  4. package/dist/common/ata.js +48 -0
  5. package/dist/common/buffer.d.ts +15 -0
  6. package/dist/common/buffer.js +118 -0
  7. package/dist/common/connection.d.ts +13 -0
  8. package/dist/common/connection.js +2 -0
  9. package/dist/common/constants.d.ts +14 -0
  10. package/dist/common/constants.js +31 -0
  11. package/dist/common/index.d.ts +6 -0
  12. package/dist/common/index.js +28 -0
  13. package/dist/common/strategy-interface.d.ts +59 -0
  14. package/dist/common/strategy-interface.js +42 -0
  15. package/dist/elemental-lend/accounts.d.ts +103 -0
  16. package/dist/elemental-lend/accounts.js +354 -0
  17. package/dist/elemental-lend/constants.d.ts +25 -0
  18. package/dist/elemental-lend/constants.js +48 -0
  19. package/dist/elemental-lend/index.d.ts +8 -0
  20. package/dist/elemental-lend/index.js +24 -0
  21. package/dist/elemental-lend/instructions.d.ts +104 -0
  22. package/dist/elemental-lend/instructions.js +266 -0
  23. package/dist/elemental-lend/jupiter-lend.d.ts +91 -0
  24. package/dist/elemental-lend/jupiter-lend.js +189 -0
  25. package/dist/elemental-lend/kamino-vault.d.ts +173 -0
  26. package/dist/elemental-lend/kamino-vault.js +483 -0
  27. package/dist/elemental-lend/pda.d.ts +12 -0
  28. package/dist/elemental-lend/pda.js +24 -0
  29. package/dist/elemental-lend/protocol-actions.d.ts +56 -0
  30. package/dist/elemental-lend/protocol-actions.js +244 -0
  31. package/dist/elemental-lend/types.d.ts +113 -0
  32. package/dist/elemental-lend/types.js +2 -0
  33. package/dist/elemental-lend-v2/accounts.d.ts +14 -0
  34. package/dist/elemental-lend-v2/accounts.js +136 -0
  35. package/dist/elemental-lend-v2/adapters.d.ts +22 -0
  36. package/dist/elemental-lend-v2/adapters.js +50 -0
  37. package/dist/elemental-lend-v2/constants.d.ts +48 -0
  38. package/dist/elemental-lend-v2/constants.js +104 -0
  39. package/dist/elemental-lend-v2/index.d.ts +8 -0
  40. package/dist/elemental-lend-v2/index.js +24 -0
  41. package/dist/elemental-lend-v2/instructions.d.ts +96 -0
  42. package/dist/elemental-lend-v2/instructions.js +190 -0
  43. package/dist/elemental-lend-v2/lut.d.ts +20 -0
  44. package/dist/elemental-lend-v2/lut.js +65 -0
  45. package/dist/elemental-lend-v2/pda.d.ts +9 -0
  46. package/dist/elemental-lend-v2/pda.js +27 -0
  47. package/dist/elemental-lend-v2/types.d.ts +105 -0
  48. package/dist/elemental-lend-v2/types.js +2 -0
  49. package/dist/elemental-lend-v2/update-aum.d.ts +29 -0
  50. package/dist/elemental-lend-v2/update-aum.js +82 -0
  51. package/dist/index.d.ts +5 -3552
  52. package/dist/index.js +37 -4454
  53. package/dist/jlpd-strategy/accounts.d.ts +83 -0
  54. package/dist/jlpd-strategy/accounts.js +216 -0
  55. package/dist/jlpd-strategy/adapter.d.ts +81 -0
  56. package/dist/jlpd-strategy/adapter.js +118 -0
  57. package/dist/jlpd-strategy/base-to-base-swap.d.ts +74 -0
  58. package/dist/jlpd-strategy/base-to-base-swap.js +205 -0
  59. package/dist/jlpd-strategy/constants.d.ts +127 -0
  60. package/dist/jlpd-strategy/constants.js +174 -0
  61. package/dist/jlpd-strategy/fluid-view.d.ts +199 -0
  62. package/dist/jlpd-strategy/fluid-view.js +799 -0
  63. package/dist/jlpd-strategy/hedge-derived.d.ts +135 -0
  64. package/dist/jlpd-strategy/hedge-derived.js +231 -0
  65. package/dist/jlpd-strategy/hedge-instructions.d.ts +210 -0
  66. package/dist/jlpd-strategy/hedge-instructions.js +300 -0
  67. package/dist/jlpd-strategy/hedge-state.d.ts +88 -0
  68. package/dist/jlpd-strategy/hedge-state.js +110 -0
  69. package/dist/jlpd-strategy/index.d.ts +17 -0
  70. package/dist/jlpd-strategy/index.js +33 -0
  71. package/dist/jlpd-strategy/instructions.d.ts +159 -0
  72. package/dist/jlpd-strategy/instructions.js +234 -0
  73. package/dist/jlpd-strategy/jlp-borrow.d.ts +63 -0
  74. package/dist/jlpd-strategy/jlp-borrow.js +87 -0
  75. package/dist/jlpd-strategy/jlp-data.d.ts +166 -0
  76. package/dist/jlpd-strategy/jlp-data.js +611 -0
  77. package/dist/jlpd-strategy/jupusd-earn.d.ts +90 -0
  78. package/dist/jlpd-strategy/jupusd-earn.js +166 -0
  79. package/dist/jlpd-strategy/live-jlp-price.d.ts +46 -0
  80. package/dist/jlpd-strategy/live-jlp-price.js +267 -0
  81. package/dist/jlpd-strategy/pda.d.ts +13 -0
  82. package/dist/jlpd-strategy/pda.js +28 -0
  83. package/dist/jlpd-strategy/settle-yield.d.ts +45 -0
  84. package/dist/jlpd-strategy/settle-yield.js +113 -0
  85. package/dist/jlpd-strategy/swap-jlp.d.ts +198 -0
  86. package/dist/jlpd-strategy/swap-jlp.js +586 -0
  87. package/dist/jlpd-strategy/types.d.ts +101 -0
  88. package/dist/jlpd-strategy/types.js +29 -0
  89. package/dist/p-stv-core/accounts.d.ts +152 -0
  90. package/dist/p-stv-core/accounts.js +407 -0
  91. package/dist/p-stv-core/constants.d.ts +138 -0
  92. package/dist/p-stv-core/constants.js +181 -0
  93. package/dist/p-stv-core/events.d.ts +7 -0
  94. package/dist/p-stv-core/events.js +246 -0
  95. package/dist/p-stv-core/index.d.ts +11 -0
  96. package/dist/p-stv-core/index.js +27 -0
  97. package/dist/p-stv-core/instructions.d.ts +637 -0
  98. package/dist/p-stv-core/instructions.js +670 -0
  99. package/dist/p-stv-core/lut.d.ts +41 -0
  100. package/dist/p-stv-core/lut.js +81 -0
  101. package/dist/p-stv-core/pda.d.ts +30 -0
  102. package/dist/p-stv-core/pda.js +65 -0
  103. package/dist/p-stv-core/prices.d.ts +20 -0
  104. package/dist/p-stv-core/prices.js +77 -0
  105. package/dist/p-stv-core/remaining-accounts.d.ts +107 -0
  106. package/dist/p-stv-core/remaining-accounts.js +326 -0
  107. package/dist/p-stv-core/send-tx.d.ts +72 -0
  108. package/dist/p-stv-core/send-tx.js +290 -0
  109. package/dist/p-stv-core/sol-wrap.d.ts +34 -0
  110. package/dist/p-stv-core/sol-wrap.js +74 -0
  111. package/dist/p-stv-core/types.d.ts +361 -0
  112. package/dist/p-stv-core/types.js +2 -0
  113. package/package.json +56 -15
  114. package/dist/index.d.mts +0 -3552
  115. package/dist/index.mjs +0 -4363
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Derived-data helpers for the native Jup-Lend hedge — frontend dashboards + driver sizing.
3
+ * Everything here is either a pure function mirroring an on-chain pure helper
4
+ * (`state/hedge_state.rs`) exactly, or a thin async composition over `fluid-view.ts` +
5
+ * `hedge-state.ts` that answers the same questions the on-chain guards answer:
6
+ * - per-slot LTV, valued on that slot's OWN pinned Fluid oracle (matches `hedge_borrow`'s /
7
+ * `hedge_withdraw_collateral`'s post-op guard basis exactly — see `fluid-view.ts`)
8
+ * - pledged collateral summed across every ENABLED slot vs `HedgeState.maxPledgedCollateralJlp`
9
+ * - swap-churn budget remaining (`maxSwapNotionalPerSettle - swapNotionalSinceSettle`)
10
+ */
11
+ import { PublicKey } from "@solana/web3.js";
12
+ import type { SolanaConnection } from "../common/connection";
13
+ import { type HedgeState, type HedgePositionSlot } from "./hedge-state";
14
+ /**
15
+ * Native decimals for each known hedge debt mint — mirrors `utils/oracle.rs`'s
16
+ * `TOKEN_DECIMALS_{BTC,ETH,SOL,JUPUSD}` constants (the four mints
17
+ * `is_known_hedge_debt_mint` accepts). Throws on an unrecognized mint.
18
+ */
19
+ export declare function debtMintDecimals(mint: PublicKey): number;
20
+ /**
21
+ * Map a `HedgePositionSlot.debtMint` to the config-owned manifest ATA its borrow/repay routes
22
+ * through — mirrors `resolve_debt_manifest_ata` exactly. Returns `PublicKey.default()` (never
23
+ * throws) for a KNOWN mint whose manifest ATA slot was never backfilled — callers must reject
24
+ * that themselves; only a genuinely UNKNOWN debt mint throws here.
25
+ */
26
+ export declare function resolveDebtManifestAta(state: HedgeState, debtMint: PublicKey): PublicKey;
27
+ /** Sum already-decoded per-slot collateral (pure, never throws — for read-only dashboards). */
28
+ export declare function sumPledgedCollateral(perSlotCollateralJlp: bigint[]): bigint;
29
+ /**
30
+ * Sum already-decoded per-slot collateral and enforce the total against
31
+ * `HedgeState.maxPledgedCollateralJlp` — mirrors `sum_and_check_pledged_collateral` exactly
32
+ * (checked addition; throws rather than wrapping past the cap). For DRIVER preflight (reject
33
+ * before submitting a tx that would revert on-chain); dashboards should use
34
+ * `sumPledgedCollateral` instead so an (unexpected) over-cap reading still renders.
35
+ */
36
+ export declare function sumAndCheckPledgedCollateral(perSlotCollateralJlp: bigint[], maxPledgedCollateralJlp: bigint): bigint;
37
+ /**
38
+ * `hedge_repay` repay-all sentinel (u64::MAX) — the only mode that guarantees `debt == 0`.
39
+ * Fund the debt ATA to the on-chain budget (ceiled reading + 0.1% + 2 units) and crank the
40
+ * permissionless `update_exchange_prices` first.
41
+ */
42
+ export declare const REPAY_ALL_SENTINEL = 18446744073709551615n;
43
+ /**
44
+ * @deprecated The on-chain clamp is GONE: `hedge_repay` now REJECTS a partial amount that fails
45
+ * its acceptance predicate instead of clamping it. Size with `maxPartialRepayNative` /
46
+ * `isPartialRepayAcceptable` below; this function survives only so old scripts still compile,
47
+ * and its output is no longer guaranteed acceptable on-chain.
48
+ */
49
+ export declare function clampRepayAmount(requested: bigint, debtBefore: bigint): bigint;
50
+ /** Fluid's minimum native amount per operate leg (`MIN_OPERATE`, pre-scale; all hedge debt mints
51
+ * are 6/8/9 decimals). Mirrors the program's `FLUID_MIN_OPERATE_NATIVE`. */
52
+ export declare const FLUID_MIN_OPERATE_NATIVE = 1000n;
53
+ /** Fluid's minimum POSITION debt in raw units (`MIN_DEBT = 1000` scaled by `10^(9−decimals)`) —
54
+ * mirrors the program's `fluid_min_debt_raw`. */
55
+ export declare function fluidMinDebtRaw(debtDecimals: number): bigint;
56
+ /** RAW debt Fluid credits for a partial payback of `x` native — mirrors the program's
57
+ * `fluid_partial_repay_credit_raw`: `floor(x·10^(9−d)·1e12 / E) − 1`. Throws when the floor term
58
+ * is 0 (an `x` too small to credit anything). */
59
+ export declare function fluidPartialRepayCreditRaw(xNative: bigint, debtDecimals: number, borrowExPrice: bigint): bigint;
60
+ /**
61
+ * Mirror of `hedge_repay`'s on-chain partial acceptance: `x ≥ MIN_OPERATE`, `C(x) ≥ 1`, and
62
+ * `C(x) + minDebtRaw ≤ netRawDebt` (no excess payback AND the residual stays at/above Fluid's
63
+ * minimum position debt). `netRawDebt` = tick-implied − dust (fluid-view's `netDebtRaw` basis).
64
+ */
65
+ export declare function isPartialRepayAcceptable(xNative: bigint, netRawDebt: bigint, debtDecimals: number, borrowExPrice: bigint): boolean;
66
+ /**
67
+ * Largest partial repay (native) the on-chain acceptance admits for `netRawDebt` at the given
68
+ * stored price — the driver's sizing cap (anything larger reverts; anything at/below is safe at
69
+ * every live price ≥ the stored one). Returns 0n when no partial is acceptable (debt too small —
70
+ * use the repay-all sentinel instead).
71
+ */
72
+ export declare function maxPartialRepayNative(netRawDebt: bigint, debtDecimals: number, borrowExPrice: bigint): bigint;
73
+ /**
74
+ * Swap-churn budget remaining before the next `settle_yield` resets the accumulator — mirrors
75
+ * `HedgeState.maxSwapNotionalPerSettle - HedgeState.swapNotionalSinceSettle` (USD, 6-dec),
76
+ * floored at 0 (the accumulator should never on-chain exceed the cap, but this stays
77
+ * fail-safe against a stale/racing read).
78
+ */
79
+ export declare function churnBudgetRemainingUsd(state: Pick<HedgeState, "maxSwapNotionalPerSettle" | "swapNotionalSinceSettle">): bigint;
80
+ /**
81
+ * `HedgeState.maxPledgedCollateralJlp` as a bigint — headroom convenience: pass the result of
82
+ * `sumAndCheckPledgedCollateral`'s successful total (or a raw sum) to get remaining pledge room.
83
+ */
84
+ export declare function pledgeHeadroomJlp(state: Pick<HedgeState, "maxPledgedCollateralJlp">, totalPledgedJlp: bigint): bigint;
85
+ /** One enabled `HedgeState.positions` slot's derived valuation. */
86
+ export interface HedgeSlotDerived {
87
+ slotIndex: number;
88
+ slot: HedgePositionSlot;
89
+ /** JLP (6-dec) pledged as collateral in this slot, interest-adjusted. */
90
+ collateralJlpNative: bigint;
91
+ /** Outstanding debt, in the debt mint's own native decimals. */
92
+ debtNative: bigint;
93
+ debtDecimals: number;
94
+ /** Liquidation-probability reading in basis points, valued on this slot's OWN Fluid oracle. */
95
+ ltvBps: number;
96
+ /** The pair-native oracle price (1e15 precision) this LTV was valued at. */
97
+ price1e15: bigint;
98
+ }
99
+ /**
100
+ * Fetch + value ONE `HedgeState.positions[slotIndex]` slot — the async convenience wrapper
101
+ * matching `hedge_borrow`'s / `hedge_withdraw_collateral`'s post-op LTV guard basis exactly
102
+ * (see `fluid-view.ts::fetchFluidSlotLtv`). Returns `null` for a disabled slot.
103
+ */
104
+ export declare function fetchHedgeSlotDerived(connection: SolanaConnection, state: HedgeState, slotIndex: number): Promise<HedgeSlotDerived | null>;
105
+ /**
106
+ * Fetch + value every ENABLED slot in `HedgeState.positions` (sequentially skips disabled
107
+ * slots; each enabled slot's fetch runs independently so one slot's RPC error does not hide the
108
+ * others — callers that want all-or-nothing should wrap in their own try/catch).
109
+ */
110
+ export declare function fetchAllHedgeSlotsDerived(connection: SolanaConnection, state: HedgeState): Promise<HedgeSlotDerived[]>;
111
+ /**
112
+ * Portfolio-level hedge exposure: total pledged JLP collateral across every enabled slot (vs
113
+ * `HedgeState.maxPledgedCollateralJlp`), and per-debt-mint net debt exposure (native units,
114
+ * keyed by the debt mint's base58 — different debt mints are never summed together, since
115
+ * they are different tokens).
116
+ */
117
+ export interface HedgeExposure {
118
+ /** Σ `collateralJlpNative` across every enabled slot. */
119
+ totalPledgedCollateralJlp: bigint;
120
+ /** `HedgeState.maxPledgedCollateralJlp - totalPledgedCollateralJlp`, floored at 0. */
121
+ pledgeHeadroomJlp: bigint;
122
+ /**
123
+ * `totalPledgedCollateralJlp > HedgeState.maxPledgedCollateralJlp` — should never be true given
124
+ * the on-chain guard (`hedge_supply_collateral` re-scans + rejects this every supply), but
125
+ * surfaced rather than thrown so a stale/racing read still renders on a dashboard.
126
+ */
127
+ pledgeCapExceeded: boolean;
128
+ /** Per-debt-mint (base58) → summed native debt across every slot borrowing that mint. */
129
+ debtByMint: Record<string, bigint>;
130
+ /** Swap-churn budget remaining (USD, 6-dec). */
131
+ churnBudgetRemainingUsd: bigint;
132
+ slots: HedgeSlotDerived[];
133
+ }
134
+ /** Compute portfolio-level hedge exposure from a fully-fetched `HedgeState`. */
135
+ export declare function fetchHedgeExposure(connection: SolanaConnection, state: HedgeState): Promise<HedgeExposure>;
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ /**
3
+ * Derived-data helpers for the native Jup-Lend hedge — frontend dashboards + driver sizing.
4
+ * Everything here is either a pure function mirroring an on-chain pure helper
5
+ * (`state/hedge_state.rs`) exactly, or a thin async composition over `fluid-view.ts` +
6
+ * `hedge-state.ts` that answers the same questions the on-chain guards answer:
7
+ * - per-slot LTV, valued on that slot's OWN pinned Fluid oracle (matches `hedge_borrow`'s /
8
+ * `hedge_withdraw_collateral`'s post-op guard basis exactly — see `fluid-view.ts`)
9
+ * - pledged collateral summed across every ENABLED slot vs `HedgeState.maxPledgedCollateralJlp`
10
+ * - swap-churn budget remaining (`maxSwapNotionalPerSettle - swapNotionalSinceSettle`)
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.FLUID_MIN_OPERATE_NATIVE = exports.REPAY_ALL_SENTINEL = void 0;
14
+ exports.debtMintDecimals = debtMintDecimals;
15
+ exports.resolveDebtManifestAta = resolveDebtManifestAta;
16
+ exports.sumPledgedCollateral = sumPledgedCollateral;
17
+ exports.sumAndCheckPledgedCollateral = sumAndCheckPledgedCollateral;
18
+ exports.clampRepayAmount = clampRepayAmount;
19
+ exports.fluidMinDebtRaw = fluidMinDebtRaw;
20
+ exports.fluidPartialRepayCreditRaw = fluidPartialRepayCreditRaw;
21
+ exports.isPartialRepayAcceptable = isPartialRepayAcceptable;
22
+ exports.maxPartialRepayNative = maxPartialRepayNative;
23
+ exports.churnBudgetRemainingUsd = churnBudgetRemainingUsd;
24
+ exports.pledgeHeadroomJlp = pledgeHeadroomJlp;
25
+ exports.fetchHedgeSlotDerived = fetchHedgeSlotDerived;
26
+ exports.fetchAllHedgeSlotsDerived = fetchAllHedgeSlotsDerived;
27
+ exports.fetchHedgeExposure = fetchHedgeExposure;
28
+ const constants_1 = require("./constants");
29
+ const hedge_state_1 = require("./hedge-state");
30
+ const fluid_view_1 = require("./fluid-view");
31
+ // ---------------------------------------------------------------------------
32
+ // Pure helpers — mirror `state/hedge_state.rs`'s free functions exactly.
33
+ // ---------------------------------------------------------------------------
34
+ /**
35
+ * Native decimals for each known hedge debt mint — mirrors `utils/oracle.rs`'s
36
+ * `TOKEN_DECIMALS_{BTC,ETH,SOL,JUPUSD}` constants (the four mints
37
+ * `is_known_hedge_debt_mint` accepts). Throws on an unrecognized mint.
38
+ */
39
+ function debtMintDecimals(mint) {
40
+ if (mint.equals(constants_1.MINT_JUPUSD))
41
+ return 6;
42
+ if (mint.equals(constants_1.MINT_WSOL))
43
+ return 9;
44
+ if (mint.equals(constants_1.MINT_WBTC))
45
+ return 8;
46
+ if (mint.equals(constants_1.MINT_WETH))
47
+ return 8;
48
+ throw new Error(`debtMintDecimals: unrecognized hedge debt mint ${mint.toBase58()}`);
49
+ }
50
+ /**
51
+ * Map a `HedgePositionSlot.debtMint` to the config-owned manifest ATA its borrow/repay routes
52
+ * through — mirrors `resolve_debt_manifest_ata` exactly. Returns `PublicKey.default()` (never
53
+ * throws) for a KNOWN mint whose manifest ATA slot was never backfilled — callers must reject
54
+ * that themselves; only a genuinely UNKNOWN debt mint throws here.
55
+ */
56
+ function resolveDebtManifestAta(state, debtMint) {
57
+ if (debtMint.equals(constants_1.MINT_JUPUSD))
58
+ return state.jupusd;
59
+ if (debtMint.equals(constants_1.MINT_WSOL))
60
+ return state.wsol;
61
+ if (debtMint.equals(constants_1.MINT_WBTC))
62
+ return state.wbtc;
63
+ if (debtMint.equals(constants_1.MINT_WETH))
64
+ return state.weth;
65
+ throw new Error(`resolveDebtManifestAta: unrecognized hedge debt mint ${debtMint.toBase58()}`);
66
+ }
67
+ /** Sum already-decoded per-slot collateral (pure, never throws — for read-only dashboards). */
68
+ function sumPledgedCollateral(perSlotCollateralJlp) {
69
+ let total = 0n;
70
+ for (const c of perSlotCollateralJlp) {
71
+ total += c;
72
+ }
73
+ return total;
74
+ }
75
+ /**
76
+ * Sum already-decoded per-slot collateral and enforce the total against
77
+ * `HedgeState.maxPledgedCollateralJlp` — mirrors `sum_and_check_pledged_collateral` exactly
78
+ * (checked addition; throws rather than wrapping past the cap). For DRIVER preflight (reject
79
+ * before submitting a tx that would revert on-chain); dashboards should use
80
+ * `sumPledgedCollateral` instead so an (unexpected) over-cap reading still renders.
81
+ */
82
+ function sumAndCheckPledgedCollateral(perSlotCollateralJlp, maxPledgedCollateralJlp) {
83
+ const total = sumPledgedCollateral(perSlotCollateralJlp);
84
+ if (total > maxPledgedCollateralJlp) {
85
+ throw new Error(`sumAndCheckPledgedCollateral: total pledged ${total} exceeds cap ${maxPledgedCollateralJlp}`);
86
+ }
87
+ return total;
88
+ }
89
+ /**
90
+ * `hedge_repay` repay-all sentinel (u64::MAX) — the only mode that guarantees `debt == 0`.
91
+ * Fund the debt ATA to the on-chain budget (ceiled reading + 0.1% + 2 units) and crank the
92
+ * permissionless `update_exchange_prices` first.
93
+ */
94
+ exports.REPAY_ALL_SENTINEL = 18446744073709551615n; // u64::MAX
95
+ /**
96
+ * @deprecated The on-chain clamp is GONE: `hedge_repay` now REJECTS a partial amount that fails
97
+ * its acceptance predicate instead of clamping it. Size with `maxPartialRepayNative` /
98
+ * `isPartialRepayAcceptable` below; this function survives only so old scripts still compile,
99
+ * and its output is no longer guaranteed acceptable on-chain.
100
+ */
101
+ function clampRepayAmount(requested, debtBefore) {
102
+ if (requested === exports.REPAY_ALL_SENTINEL)
103
+ return exports.REPAY_ALL_SENTINEL;
104
+ return requested < debtBefore ? requested : debtBefore;
105
+ }
106
+ /** Fluid's minimum native amount per operate leg (`MIN_OPERATE`, pre-scale; all hedge debt mints
107
+ * are 6/8/9 decimals). Mirrors the program's `FLUID_MIN_OPERATE_NATIVE`. */
108
+ exports.FLUID_MIN_OPERATE_NATIVE = 1000n;
109
+ const EX_PRICE_PRECISION = 1000000000000n; // 1e12
110
+ const FLUID_MAX_TOKEN_DECIMALS = 9;
111
+ function fluidScale(debtDecimals) {
112
+ if (!Number.isInteger(debtDecimals) || debtDecimals < 4 || debtDecimals > FLUID_MAX_TOKEN_DECIMALS) {
113
+ throw new RangeError(`fluidScale: unsupported debt decimals ${debtDecimals}`);
114
+ }
115
+ return 10n ** BigInt(FLUID_MAX_TOKEN_DECIMALS - debtDecimals);
116
+ }
117
+ /** Fluid's minimum POSITION debt in raw units (`MIN_DEBT = 1000` scaled by `10^(9−decimals)`) —
118
+ * mirrors the program's `fluid_min_debt_raw`. */
119
+ function fluidMinDebtRaw(debtDecimals) {
120
+ return 1000n * fluidScale(debtDecimals);
121
+ }
122
+ /** RAW debt Fluid credits for a partial payback of `x` native — mirrors the program's
123
+ * `fluid_partial_repay_credit_raw`: `floor(x·10^(9−d)·1e12 / E) − 1`. Throws when the floor term
124
+ * is 0 (an `x` too small to credit anything). */
125
+ function fluidPartialRepayCreditRaw(xNative, debtDecimals, borrowExPrice) {
126
+ const floored = (xNative * fluidScale(debtDecimals) * EX_PRICE_PRECISION) / borrowExPrice;
127
+ if (floored < 1n)
128
+ throw new Error("fluidPartialRepayCreditRaw: credit floors to zero");
129
+ return floored - 1n;
130
+ }
131
+ /**
132
+ * Mirror of `hedge_repay`'s on-chain partial acceptance: `x ≥ MIN_OPERATE`, `C(x) ≥ 1`, and
133
+ * `C(x) + minDebtRaw ≤ netRawDebt` (no excess payback AND the residual stays at/above Fluid's
134
+ * minimum position debt). `netRawDebt` = tick-implied − dust (fluid-view's `netDebtRaw` basis).
135
+ */
136
+ function isPartialRepayAcceptable(xNative, netRawDebt, debtDecimals, borrowExPrice) {
137
+ if (xNative < exports.FLUID_MIN_OPERATE_NATIVE)
138
+ return false;
139
+ let credit;
140
+ try {
141
+ credit = fluidPartialRepayCreditRaw(xNative, debtDecimals, borrowExPrice);
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ return credit >= 1n && credit + fluidMinDebtRaw(debtDecimals) <= netRawDebt;
147
+ }
148
+ /**
149
+ * Largest partial repay (native) the on-chain acceptance admits for `netRawDebt` at the given
150
+ * stored price — the driver's sizing cap (anything larger reverts; anything at/below is safe at
151
+ * every live price ≥ the stored one). Returns 0n when no partial is acceptable (debt too small —
152
+ * use the repay-all sentinel instead).
153
+ */
154
+ function maxPartialRepayNative(netRawDebt, debtDecimals, borrowExPrice) {
155
+ const minDebt = fluidMinDebtRaw(debtDecimals);
156
+ if (netRawDebt <= minDebt)
157
+ return 0n;
158
+ const scale = fluidScale(debtDecimals);
159
+ // Invert C(x) ≤ netRaw − minDebt: x ≤ (netRaw − minDebt + 1)·E / (1e12·scale); verify + step
160
+ // down for the integer-floor edge.
161
+ let x = ((netRawDebt - minDebt + 1n) * borrowExPrice) / (EX_PRICE_PRECISION * scale);
162
+ while (x >= exports.FLUID_MIN_OPERATE_NATIVE && !isPartialRepayAcceptable(x, netRawDebt, debtDecimals, borrowExPrice)) {
163
+ x -= 1n;
164
+ }
165
+ return x >= exports.FLUID_MIN_OPERATE_NATIVE ? x : 0n;
166
+ }
167
+ /**
168
+ * Swap-churn budget remaining before the next `settle_yield` resets the accumulator — mirrors
169
+ * `HedgeState.maxSwapNotionalPerSettle - HedgeState.swapNotionalSinceSettle` (USD, 6-dec),
170
+ * floored at 0 (the accumulator should never on-chain exceed the cap, but this stays
171
+ * fail-safe against a stale/racing read).
172
+ */
173
+ function churnBudgetRemainingUsd(state) {
174
+ const max = BigInt(state.maxSwapNotionalPerSettle.toString());
175
+ const since = BigInt(state.swapNotionalSinceSettle.toString());
176
+ const remaining = max - since;
177
+ return remaining > 0n ? remaining : 0n;
178
+ }
179
+ /**
180
+ * `HedgeState.maxPledgedCollateralJlp` as a bigint — headroom convenience: pass the result of
181
+ * `sumAndCheckPledgedCollateral`'s successful total (or a raw sum) to get remaining pledge room.
182
+ */
183
+ function pledgeHeadroomJlp(state, totalPledgedJlp) {
184
+ const cap = BigInt(state.maxPledgedCollateralJlp.toString());
185
+ const headroom = cap - totalPledgedJlp;
186
+ return headroom > 0n ? headroom : 0n;
187
+ }
188
+ /**
189
+ * Fetch + value ONE `HedgeState.positions[slotIndex]` slot — the async convenience wrapper
190
+ * matching `hedge_borrow`'s / `hedge_withdraw_collateral`'s post-op LTV guard basis exactly
191
+ * (see `fluid-view.ts::fetchFluidSlotLtv`). Returns `null` for a disabled slot.
192
+ */
193
+ async function fetchHedgeSlotDerived(connection, state, slotIndex) {
194
+ if (slotIndex < 0 || slotIndex >= constants_1.MAX_HEDGE_POSITIONS) {
195
+ throw new Error(`fetchHedgeSlotDerived: slotIndex ${slotIndex} out of bounds [0, ${constants_1.MAX_HEDGE_POSITIONS})`);
196
+ }
197
+ const slot = state.positions[slotIndex];
198
+ if ((0, hedge_state_1.isHedgePositionSlotDisabled)(slot))
199
+ return null;
200
+ const decimals = debtMintDecimals(slot.debtMint);
201
+ const { ltvBps, debtNative, collateralJlpNative, price1e15 } = await (0, fluid_view_1.fetchFluidSlotLtv)(connection, slot, decimals);
202
+ return { slotIndex, slot, collateralJlpNative, debtNative, debtDecimals: decimals, ltvBps, price1e15 };
203
+ }
204
+ /**
205
+ * Fetch + value every ENABLED slot in `HedgeState.positions` (sequentially skips disabled
206
+ * slots; each enabled slot's fetch runs independently so one slot's RPC error does not hide the
207
+ * others — callers that want all-or-nothing should wrap in their own try/catch).
208
+ */
209
+ async function fetchAllHedgeSlotsDerived(connection, state) {
210
+ const results = await Promise.all(state.positions.map((slot, slotIndex) => (0, hedge_state_1.isHedgePositionSlotDisabled)(slot) ? Promise.resolve(null) : fetchHedgeSlotDerived(connection, state, slotIndex)));
211
+ return results.filter((r) => r !== null);
212
+ }
213
+ /** Compute portfolio-level hedge exposure from a fully-fetched `HedgeState`. */
214
+ async function fetchHedgeExposure(connection, state) {
215
+ const slots = await fetchAllHedgeSlotsDerived(connection, state);
216
+ const totalPledgedCollateralJlp = sumPledgedCollateral(slots.map((s) => s.collateralJlpNative));
217
+ const cap = BigInt(state.maxPledgedCollateralJlp.toString());
218
+ const debtByMint = {};
219
+ for (const s of slots) {
220
+ const key = s.slot.debtMint.toBase58();
221
+ debtByMint[key] = (debtByMint[key] ?? 0n) + s.debtNative;
222
+ }
223
+ return {
224
+ totalPledgedCollateralJlp,
225
+ pledgeHeadroomJlp: cap - totalPledgedCollateralJlp > 0n ? cap - totalPledgedCollateralJlp : 0n,
226
+ pledgeCapExceeded: totalPledgedCollateralJlp > cap,
227
+ debtByMint,
228
+ churnBudgetRemainingUsd: churnBudgetRemainingUsd(state),
229
+ slots,
230
+ };
231
+ }
@@ -0,0 +1,210 @@
1
+ import { PublicKey, TransactionInstruction, AccountMeta } from "@solana/web3.js";
2
+ import BN from "bn.js";
3
+ import type { HedgePositionSlot } from "./hedge-state";
4
+ /** Common account inputs shared by every native hedge op. */
5
+ export interface HedgeOpAccounts {
6
+ manager: PublicKey;
7
+ config: PublicKey;
8
+ managerRole: PublicKey;
9
+ hedgeState: PublicKey;
10
+ /** JLP source (supply/borrow/repay) or destination (withdraw) ATA — must equal `JlpdConfig.vault_jlp_ata`. */
11
+ jlpSourceAta: PublicKey;
12
+ /** This slot's debt-manifest ATA — resolved from `HedgeState` off-chain (`resolveDebtManifestAta` in hedge-derived.ts). */
13
+ debtAta: PublicKey;
14
+ jlpMint: PublicKey;
15
+ /** This slot's `HedgePositionSlot.debtMint`. */
16
+ debtMint: PublicKey;
17
+ /** This slot's `HedgePositionSlot.fluidOracle`. */
18
+ fluidOracle: PublicKey;
19
+ /** This slot's `HedgePositionSlot.borrowPosition`. */
20
+ borrowPosition: PublicKey;
21
+ /** This slot's `HedgePositionSlot.vaultConfig`. */
22
+ vaultConfig: PublicKey;
23
+ /** This slot's `HedgePositionSlot.vaultState`. */
24
+ vaultState: PublicKey;
25
+ jupLendBorrowProgram?: PublicKey;
26
+ tokenProgram?: PublicKey;
27
+ associatedTokenProgram?: PublicKey;
28
+ systemProgram?: PublicKey;
29
+ /**
30
+ * Fully-ordered remaining accounts for this op (see this module's doc comment for the exact
31
+ * per-op sub-partition). The caller assembles these (Fluid operate() passthrough + oracle
32
+ * feed / pledge-scan slices); this builder does not.
33
+ */
34
+ remainingAccounts?: AccountMeta[];
35
+ }
36
+ export interface CreateHedgeSupplyCollateralIxArgs extends HedgeOpAccounts {
37
+ slotIndex: number;
38
+ /** JLP (base units, 6 decimals) to pledge as collateral. */
39
+ amount: bigint | BN;
40
+ }
41
+ /** Build the on-chain `hedge_supply_collateral` instruction. */
42
+ export declare function createHedgeSupplyCollateralIx(args: CreateHedgeSupplyCollateralIxArgs, programId?: PublicKey): TransactionInstruction;
43
+ export interface CreateHedgeBorrowIxArgs extends HedgeOpAccounts {
44
+ slotIndex: number;
45
+ /** Debt-mint-native amount to borrow. */
46
+ amount: bigint | BN;
47
+ }
48
+ /** Build the on-chain `hedge_borrow` instruction. */
49
+ export declare function createHedgeBorrowIx(args: CreateHedgeBorrowIxArgs, programId?: PublicKey): TransactionInstruction;
50
+ export interface CreateHedgeRepayIxArgs extends HedgeOpAccounts {
51
+ slotIndex: number;
52
+ /** Debt-mint-native amount REQUESTED to repay — must satisfy the on-chain acceptance predicate
53
+ * (no clamping), or the repay-all sentinel. */
54
+ amount: bigint | BN;
55
+ /** The position's canonical Fluid Tick — `deriveFluidTickPda(vaultId, position.tick)` /
56
+ * `settleTickPdaForPosition(position)` from a fresh position read. The program validates it
57
+ * and rejects a liquidation-stale position outright. */
58
+ fluidTick: PublicKey;
59
+ }
60
+ /** Build the on-chain `hedge_repay` instruction. */
61
+ export declare function createHedgeRepayIx(args: CreateHedgeRepayIxArgs, programId?: PublicKey): TransactionInstruction;
62
+ export interface CreateHedgeWithdrawCollateralIxArgs extends HedgeOpAccounts {
63
+ slotIndex: number;
64
+ /** JLP (base units, 6 decimals) to withdraw from the position's collateral. */
65
+ amount: bigint | BN;
66
+ }
67
+ /** Build the on-chain `hedge_withdraw_collateral` instruction. */
68
+ export declare function createHedgeWithdrawCollateralIx(args: CreateHedgeWithdrawCollateralIxArgs, programId?: PublicKey): TransactionInstruction;
69
+ /**
70
+ * Mirrors the on-chain `HedgeManifestRole` enum exactly (`instructions/hedge/hedge_swap.rs`) —
71
+ * Borsh-serializes as a single `u8` by declaration order, which coincides with each variant's
72
+ * explicit `= N` discriminant (verified by the Rust module's own
73
+ * `test_borsh_round_trip_matches_declared_discriminants`).
74
+ */
75
+ export declare enum HedgeManifestRole {
76
+ JupUsd = 0,
77
+ JupSol = 1,
78
+ Wbtc = 2,
79
+ Weth = 3,
80
+ Wsol = 4,
81
+ JlJupUsd = 5,
82
+ JlWbtc = 6,
83
+ JlWeth = 7
84
+ }
85
+ /** Account inputs for `createHedgeSwapIx`. */
86
+ export interface CreateHedgeSwapIxArgs {
87
+ manager: PublicKey;
88
+ config: PublicKey;
89
+ managerRole: PublicKey;
90
+ hedgeState: PublicKey;
91
+ /** Must equal `manifest_role_ata(hedge_state, params.srcRole)`. */
92
+ srcAta: PublicKey;
93
+ /** Must equal `manifest_role_ata(hedge_state, params.dstRole)`. */
94
+ dstAta: PublicKey;
95
+ /** Doves oracle for `srcRole` — any account if `srcRole` isn't Doves-priced (Wbtc/Weth/Wsol/JupSol). */
96
+ priceOracleSrc: PublicKey;
97
+ /** Doves oracle for `dstRole` — same rules as `priceOracleSrc`. */
98
+ priceOracleDst: PublicKey;
99
+ /** StrategyState PDA for `srcRole`'s base asset — any account if unused. */
100
+ strategyStateSrc: PublicKey;
101
+ /** StrategyState PDA for `dstRole`'s base asset — any account if unused. */
102
+ strategyStateDst: PublicKey;
103
+ /** Jup-Lend Earn `lending` account for `srcRole` if it's an fToken role — any account otherwise. */
104
+ lendingSrc: PublicKey;
105
+ /** Jup-Lend Earn `lending` account for `dstRole` — same rules as `lendingSrc`. */
106
+ lendingDst: PublicKey;
107
+ /**
108
+ * JupSOL Sanctum stake-pool account — only actually validated on-chain when `srcRole` or
109
+ * `dstRole` is `HedgeManifestRole.JupSol`. Defaults to the pinned `JUPSOL_STAKE_POOL_ACCOUNT` so
110
+ * callers whose swap never touches JupSol don't need to think about it.
111
+ */
112
+ jupsolRate?: PublicKey;
113
+ jupiterProgram?: PublicKey;
114
+ srcRole: HedgeManifestRole;
115
+ dstRole: HedgeManifestRole;
116
+ /** Amount of `srcRole` to spend (native units). */
117
+ amountIn: bigint | BN;
118
+ /** Caller-supplied minimum acceptable output — the on-chain floor is `max(minOut, oracle_floor)`. */
119
+ minOut: bigint | BN;
120
+ /** Jupiter swap instruction data (discriminator + route). Can be empty on devnet/localnet. */
121
+ jupiterData: Buffer | Uint8Array;
122
+ /**
123
+ * Fully-ordered Jupiter route accounts (source must be `srcAta`, destination must be `dstAta`) —
124
+ * unchanged passthrough, exactly like `createBaseToBaseSwapIx`'s `remainingAccounts`.
125
+ */
126
+ remainingAccounts?: AccountMeta[];
127
+ }
128
+ /**
129
+ * Build the on-chain `hedge_swap` instruction — see this module's `hedge_swap` section doc
130
+ * comment above for the full account-order rationale and the JupSOL stake-pool default.
131
+ *
132
+ * Instruction data layout (Anchor Borsh, `HedgeSwapParams`):
133
+ * [8-byte disc, 1-byte src_role, 1-byte dst_role, 8-byte amount_in (LE), 8-byte min_out (LE),
134
+ * 4-byte jupiter_data_len (LE), ...jupiter_data_bytes]
135
+ *
136
+ * A JupSol leg requires a FRESH (epoch-current) `jupsolRate` stake-pool account — a stale pool
137
+ * reverts `StaleJupSolStakePool` on-chain.
138
+ */
139
+ export declare function createHedgeSwapIx(args: CreateHedgeSwapIxArgs, programId?: PublicKey): TransactionInstruction;
140
+ /**
141
+ * One `HedgePositionSlot` update param — mirrors the on-chain `HedgePositionSlotParams`
142
+ * (init_or_update_hedge_state.rs). Structurally identical to the decode-side `HedgePositionSlot`
143
+ * (hedge-state.ts): re-exported under the Rust param-struct name for call-site clarity.
144
+ */
145
+ export type HedgePositionSlotParams = HedgePositionSlot;
146
+ /** Account inputs + Borsh params for `createInitOrUpdateHedgeStateIx`. */
147
+ export interface InitOrUpdateHedgeStateArgs {
148
+ /** Rent payer; must equal `JlpdConfig.admin` on both init and update. Signer + writable. */
149
+ payer: PublicKey;
150
+ /** The JLPD Config PDA (already initialized). */
151
+ config: PublicKey;
152
+ /** The HedgeState PDA — seeds `["hedge", config]` (`findHedgeStatePda` in hedge-state.ts). */
153
+ hedgeState: PublicKey;
154
+ tokenProgram?: PublicKey;
155
+ systemProgram?: PublicKey;
156
+ /**
157
+ * Exactly `MAX_HEDGE_POSITIONS` (4) entries, slot-index order, or omitted/empty to leave every
158
+ * slot untouched. `null` at index `i` leaves `HedgeState.positions[i]` as-is (Borsh `None`); a
159
+ * `HedgePositionSlotParams` value fully replaces that slot (Borsh `Some`) — there is no partial
160
+ * per-field slot update on-chain.
161
+ */
162
+ positions?: (HedgePositionSlotParams | null)[];
163
+ /** Config-owned JupUSD ATA (compile-time mint `MINT_JUPUSD`). `null`/omitted = unchanged. */
164
+ jupusd?: PublicKey | null;
165
+ /** Config-owned JupSOL ATA (compile-time mint `MINT_JUPSOL`). `null`/omitted = unchanged. */
166
+ jupsol?: PublicKey | null;
167
+ /** Config-owned wBTC ATA (compile-time mint `MINT_WBTC`). `null`/omitted = unchanged. */
168
+ wbtc?: PublicKey | null;
169
+ /** Config-owned wETH ATA (compile-time mint `MINT_WETH`). `null`/omitted = unchanged. */
170
+ weth?: PublicKey | null;
171
+ /** Config-owned wSOL ATA (compile-time mint `MINT_WSOL`). `null`/omitted = unchanged. */
172
+ wsol?: PublicKey | null;
173
+ /** Config-owned JupUSD Earn fToken ATA. `null`/omitted = unchanged. */
174
+ jlJupusd?: PublicKey | null;
175
+ /** Config-owned wBTC Earn fToken ATA (disabled until wired). `null`/omitted = unchanged. */
176
+ jlWbtc?: PublicKey | null;
177
+ /** Config-owned wETH Earn fToken ATA (disabled until wired). `null`/omitted = unchanged. */
178
+ jlWeth?: PublicKey | null;
179
+ /** Admin-set JupUSD Earn fToken mint (`Pubkey.default()` = unset). `null`/omitted = unchanged. */
180
+ jlJupusdMint?: PublicKey | null;
181
+ /** Admin-set wBTC Earn fToken mint. `null`/omitted = unchanged. */
182
+ jlWbtcMint?: PublicKey | null;
183
+ /** Admin-set wETH Earn fToken mint. `null`/omitted = unchanged. */
184
+ jlWethMint?: PublicKey | null;
185
+ /** JupUSD Earn `lending` rate-source account. `null`/omitted = unchanged. */
186
+ jlJupusdLending?: PublicKey | null;
187
+ /** wBTC Earn `lending` rate-source account. `null`/omitted = unchanged. */
188
+ jlWbtcLending?: PublicKey | null;
189
+ /** wETH Earn `lending` rate-source account. `null`/omitted = unchanged. */
190
+ jlWethLending?: PublicKey | null;
191
+ /** JLP-native pledge cap (base units, 6 decimals). `null`/omitted = unchanged (init: 0). */
192
+ maxPledgedCollateralJlp?: bigint | BN | null;
193
+ /** Per-settle swap-churn budget (USD, 6-dec). `null`/omitted = unchanged (init: 0). */
194
+ maxSwapNotionalPerSettle?: bigint | BN | null;
195
+ /** Pair-native per-position LTV cap, bps (0..=`MAX_HEDGE_LTV_BPS`). `null`/omitted = unchanged (init: 0). */
196
+ maxLtvBps?: number | null;
197
+ /** Hedge master switch. `null`/omitted = unchanged (init: false). */
198
+ enabled?: boolean | null;
199
+ /**
200
+ * Config-owned token accounts backing any manifest ATA slot set to a NEW value this call
201
+ * (order-independent, matched by pubkey on-chain). An unchanged slot needs none.
202
+ */
203
+ remainingAccounts?: AccountMeta[];
204
+ }
205
+ /**
206
+ * Build the on-chain `init_or_update_hedge_state` instruction (provisions/updates the singleton
207
+ * `HedgeState` PDA). See this section's module doc comment above for the full account list and
208
+ * Borsh field order.
209
+ */
210
+ export declare function createInitOrUpdateHedgeStateIx(args: InitOrUpdateHedgeStateArgs, programId?: PublicKey): TransactionInstruction;