@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.
- package/LICENSE +201 -0
- package/README.md +185 -404
- package/dist/common/ata.d.ts +26 -0
- package/dist/common/ata.js +48 -0
- package/dist/common/buffer.d.ts +15 -0
- package/dist/common/buffer.js +118 -0
- package/dist/common/connection.d.ts +13 -0
- package/dist/common/connection.js +2 -0
- package/dist/common/constants.d.ts +14 -0
- package/dist/common/constants.js +31 -0
- package/dist/common/index.d.ts +6 -0
- package/dist/common/index.js +28 -0
- package/dist/common/strategy-interface.d.ts +59 -0
- package/dist/common/strategy-interface.js +42 -0
- package/dist/elemental-lend/accounts.d.ts +103 -0
- package/dist/elemental-lend/accounts.js +354 -0
- package/dist/elemental-lend/constants.d.ts +25 -0
- package/dist/elemental-lend/constants.js +48 -0
- package/dist/elemental-lend/index.d.ts +8 -0
- package/dist/elemental-lend/index.js +24 -0
- package/dist/elemental-lend/instructions.d.ts +104 -0
- package/dist/elemental-lend/instructions.js +266 -0
- package/dist/elemental-lend/jupiter-lend.d.ts +91 -0
- package/dist/elemental-lend/jupiter-lend.js +189 -0
- package/dist/elemental-lend/kamino-vault.d.ts +173 -0
- package/dist/elemental-lend/kamino-vault.js +483 -0
- package/dist/elemental-lend/pda.d.ts +12 -0
- package/dist/elemental-lend/pda.js +24 -0
- package/dist/elemental-lend/protocol-actions.d.ts +56 -0
- package/dist/elemental-lend/protocol-actions.js +244 -0
- package/dist/elemental-lend/types.d.ts +113 -0
- package/dist/elemental-lend/types.js +2 -0
- package/dist/elemental-lend-v2/accounts.d.ts +14 -0
- package/dist/elemental-lend-v2/accounts.js +136 -0
- package/dist/elemental-lend-v2/adapters.d.ts +22 -0
- package/dist/elemental-lend-v2/adapters.js +50 -0
- package/dist/elemental-lend-v2/constants.d.ts +48 -0
- package/dist/elemental-lend-v2/constants.js +104 -0
- package/dist/elemental-lend-v2/index.d.ts +8 -0
- package/dist/elemental-lend-v2/index.js +24 -0
- package/dist/elemental-lend-v2/instructions.d.ts +96 -0
- package/dist/elemental-lend-v2/instructions.js +190 -0
- package/dist/elemental-lend-v2/lut.d.ts +20 -0
- package/dist/elemental-lend-v2/lut.js +65 -0
- package/dist/elemental-lend-v2/pda.d.ts +9 -0
- package/dist/elemental-lend-v2/pda.js +27 -0
- package/dist/elemental-lend-v2/types.d.ts +105 -0
- package/dist/elemental-lend-v2/types.js +2 -0
- package/dist/elemental-lend-v2/update-aum.d.ts +29 -0
- package/dist/elemental-lend-v2/update-aum.js +82 -0
- package/dist/index.d.ts +5 -3552
- package/dist/index.js +37 -4454
- package/dist/jlpd-strategy/accounts.d.ts +83 -0
- package/dist/jlpd-strategy/accounts.js +216 -0
- package/dist/jlpd-strategy/adapter.d.ts +81 -0
- package/dist/jlpd-strategy/adapter.js +118 -0
- package/dist/jlpd-strategy/base-to-base-swap.d.ts +74 -0
- package/dist/jlpd-strategy/base-to-base-swap.js +205 -0
- package/dist/jlpd-strategy/constants.d.ts +127 -0
- package/dist/jlpd-strategy/constants.js +174 -0
- package/dist/jlpd-strategy/fluid-view.d.ts +199 -0
- package/dist/jlpd-strategy/fluid-view.js +799 -0
- package/dist/jlpd-strategy/hedge-derived.d.ts +135 -0
- package/dist/jlpd-strategy/hedge-derived.js +231 -0
- package/dist/jlpd-strategy/hedge-instructions.d.ts +210 -0
- package/dist/jlpd-strategy/hedge-instructions.js +300 -0
- package/dist/jlpd-strategy/hedge-state.d.ts +88 -0
- package/dist/jlpd-strategy/hedge-state.js +110 -0
- package/dist/jlpd-strategy/index.d.ts +17 -0
- package/dist/jlpd-strategy/index.js +33 -0
- package/dist/jlpd-strategy/instructions.d.ts +159 -0
- package/dist/jlpd-strategy/instructions.js +234 -0
- package/dist/jlpd-strategy/jlp-borrow.d.ts +63 -0
- package/dist/jlpd-strategy/jlp-borrow.js +87 -0
- package/dist/jlpd-strategy/jlp-data.d.ts +166 -0
- package/dist/jlpd-strategy/jlp-data.js +611 -0
- package/dist/jlpd-strategy/jupusd-earn.d.ts +90 -0
- package/dist/jlpd-strategy/jupusd-earn.js +166 -0
- package/dist/jlpd-strategy/live-jlp-price.d.ts +46 -0
- package/dist/jlpd-strategy/live-jlp-price.js +267 -0
- package/dist/jlpd-strategy/pda.d.ts +13 -0
- package/dist/jlpd-strategy/pda.js +28 -0
- package/dist/jlpd-strategy/settle-yield.d.ts +45 -0
- package/dist/jlpd-strategy/settle-yield.js +113 -0
- package/dist/jlpd-strategy/swap-jlp.d.ts +198 -0
- package/dist/jlpd-strategy/swap-jlp.js +586 -0
- package/dist/jlpd-strategy/types.d.ts +101 -0
- package/dist/jlpd-strategy/types.js +29 -0
- package/dist/p-stv-core/accounts.d.ts +152 -0
- package/dist/p-stv-core/accounts.js +407 -0
- package/dist/p-stv-core/constants.d.ts +138 -0
- package/dist/p-stv-core/constants.js +181 -0
- package/dist/p-stv-core/events.d.ts +7 -0
- package/dist/p-stv-core/events.js +246 -0
- package/dist/p-stv-core/index.d.ts +11 -0
- package/dist/p-stv-core/index.js +27 -0
- package/dist/p-stv-core/instructions.d.ts +637 -0
- package/dist/p-stv-core/instructions.js +670 -0
- package/dist/p-stv-core/lut.d.ts +41 -0
- package/dist/p-stv-core/lut.js +81 -0
- package/dist/p-stv-core/pda.d.ts +30 -0
- package/dist/p-stv-core/pda.js +65 -0
- package/dist/p-stv-core/prices.d.ts +20 -0
- package/dist/p-stv-core/prices.js +77 -0
- package/dist/p-stv-core/remaining-accounts.d.ts +107 -0
- package/dist/p-stv-core/remaining-accounts.js +326 -0
- package/dist/p-stv-core/send-tx.d.ts +72 -0
- package/dist/p-stv-core/send-tx.js +290 -0
- package/dist/p-stv-core/sol-wrap.d.ts +34 -0
- package/dist/p-stv-core/sol-wrap.js +74 -0
- package/dist/p-stv-core/types.d.ts +361 -0
- package/dist/p-stv-core/types.js +2 -0
- package/package.json +56 -15
- package/dist/index.d.mts +0 -3552
- package/dist/index.mjs +0 -4363
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jupiter Lend Earn SDK helpers for JLPD Strategy.
|
|
3
|
+
*
|
|
4
|
+
* Provides position reading and APR computation for the JupUSD Earn
|
|
5
|
+
* pool used by the JLP Borrow / JupUSD Earn route.
|
|
6
|
+
*
|
|
7
|
+
* Reuses the JupUSD pool config from elemental-lend/jupiter-lend.ts
|
|
8
|
+
* since it's the same Jupiter Lend Earn program and pool.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Read-only utilities for displaying JupUSD Earn positions. This module exports
|
|
12
|
+
* **no instruction builders** — all on-chain operations against the Jupiter
|
|
13
|
+
* Lend Earn program are routed through `adapter.ts`. The exports here are:
|
|
14
|
+
*
|
|
15
|
+
* - Static program / account constants for the JupUSD Earn pool
|
|
16
|
+
* - `computeExchangeRate`, `computeFTokenValue`, `computeEarnApr` — math
|
|
17
|
+
* - `fetchEarnPosition` — read-only position fetcher
|
|
18
|
+
*
|
|
19
|
+
* Anything new that needs to *send transactions* should live in `adapter.ts`.
|
|
20
|
+
*/
|
|
21
|
+
import { PublicKey } from "@solana/web3.js";
|
|
22
|
+
import BN from "bn.js";
|
|
23
|
+
import type { SolanaConnection } from "../common/connection";
|
|
24
|
+
import { JUP_LEND_EARN_PROGRAM } from "../elemental-lend/constants";
|
|
25
|
+
/**
|
|
26
|
+
* Jupiter Lend Earn program ID. Re-exported from `elemental-lend/constants`
|
|
27
|
+
* so callers of `jlpd-strategy/jupusd-earn` can reach it without an extra
|
|
28
|
+
* import path.
|
|
29
|
+
*/
|
|
30
|
+
export { JUP_LEND_EARN_PROGRAM };
|
|
31
|
+
export declare const JUPUSD_LENDING: PublicKey;
|
|
32
|
+
export declare const JUPUSD_FTOKEN_MINT: PublicKey;
|
|
33
|
+
export declare const JUPUSD_RESERVES_LIQUIDITY: PublicKey;
|
|
34
|
+
export declare const JUPUSD_SUPPLY_POS_ON_LIQ: PublicKey;
|
|
35
|
+
export declare const JUPUSD_RATE_MODEL: PublicKey;
|
|
36
|
+
export declare const JUPUSD_VAULT: PublicKey;
|
|
37
|
+
export declare const JUPUSD_REWARDS_RATE_MODEL: PublicKey;
|
|
38
|
+
export declare const JUPUSD_LENDING_ADMIN: PublicKey;
|
|
39
|
+
/**
|
|
40
|
+
* Read the earn exchange rate from lending account + rewards model.
|
|
41
|
+
* Returns the rate scaled to 1e12.
|
|
42
|
+
*
|
|
43
|
+
* Jupiter Lend Earn lending account layout (relevant fields):
|
|
44
|
+
* [115..123] baseExchangePrice u64 (1e12 precision)
|
|
45
|
+
* [123..131] lastUpdate u64 (unix seconds)
|
|
46
|
+
*
|
|
47
|
+
* Jupiter Lend rewards rate model layout (relevant fields):
|
|
48
|
+
* [ 56.. 64] startTime u64 (unix seconds)
|
|
49
|
+
* [ 64.. 72] yearlyReward u64 (rewards distributed per year)
|
|
50
|
+
*/
|
|
51
|
+
export declare function computeExchangeRate(lendingData: Buffer, rewardsModelData: Buffer, fTokenTotalSupply: BN, currentTimestamp: number): bigint;
|
|
52
|
+
/**
|
|
53
|
+
* Compute the value of fTokens in JupUSD (native 6-decimal).
|
|
54
|
+
*/
|
|
55
|
+
export declare function computeFTokenValue(fTokenBalance: BN, exchangeRate: bigint): BN;
|
|
56
|
+
export interface EarnAprBreakdown {
|
|
57
|
+
lendingApr: number;
|
|
58
|
+
rewardsApr: number;
|
|
59
|
+
totalApr: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Compute earn APR breakdown: base lending + rewards.
|
|
63
|
+
*
|
|
64
|
+
* Total APR is derived by projecting the exchange rate 1 year forward
|
|
65
|
+
* (captures both lending yield and rewards). Rewards APR is isolated
|
|
66
|
+
* from yearly_reward / total_assets. Base = total - rewards.
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* Compute earn APR breakdown: base lending + rewards.
|
|
70
|
+
*
|
|
71
|
+
* Reads the liquidity pool's supply rate from the liquidity account,
|
|
72
|
+
* and the rewards rate from the rewards model. Requires the liquidity
|
|
73
|
+
* account data as an additional parameter.
|
|
74
|
+
*
|
|
75
|
+
* @param rewardsModelData - Rewards rate model account data
|
|
76
|
+
* @param fTokenTotalSupply - fToken total supply (from mint)
|
|
77
|
+
* @param tokenExchangePrice - From lending account offset 115
|
|
78
|
+
* @param liquiditySupplyRate - Supply rate from liquidity pool (pass 0 if unknown)
|
|
79
|
+
*/
|
|
80
|
+
export declare function computeEarnApr(rewardsModelData: Buffer, fTokenTotalSupply: BN, tokenExchangePrice: bigint, liquiditySupplyRate?: number): EarnAprBreakdown;
|
|
81
|
+
export interface EarnPositionInfo {
|
|
82
|
+
fTokenBalance: BN;
|
|
83
|
+
jupusdValue: BN;
|
|
84
|
+
apr: EarnAprBreakdown;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Fetch the earn position for a jlpd_config PDA.
|
|
88
|
+
* Returns null if no fToken ATA exists.
|
|
89
|
+
*/
|
|
90
|
+
export declare function fetchEarnPosition(connection: SolanaConnection, fTokenAta: PublicKey): Promise<EarnPositionInfo | null>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Jupiter Lend Earn SDK helpers for JLPD Strategy.
|
|
4
|
+
*
|
|
5
|
+
* Provides position reading and APR computation for the JupUSD Earn
|
|
6
|
+
* pool used by the JLP Borrow / JupUSD Earn route.
|
|
7
|
+
*
|
|
8
|
+
* Reuses the JupUSD pool config from elemental-lend/jupiter-lend.ts
|
|
9
|
+
* since it's the same Jupiter Lend Earn program and pool.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Read-only utilities for displaying JupUSD Earn positions. This module exports
|
|
13
|
+
* **no instruction builders** — all on-chain operations against the Jupiter
|
|
14
|
+
* Lend Earn program are routed through `adapter.ts`. The exports here are:
|
|
15
|
+
*
|
|
16
|
+
* - Static program / account constants for the JupUSD Earn pool
|
|
17
|
+
* - `computeExchangeRate`, `computeFTokenValue`, `computeEarnApr` — math
|
|
18
|
+
* - `fetchEarnPosition` — read-only position fetcher
|
|
19
|
+
*
|
|
20
|
+
* Anything new that needs to *send transactions* should live in `adapter.ts`.
|
|
21
|
+
*/
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.JUPUSD_LENDING_ADMIN = exports.JUPUSD_REWARDS_RATE_MODEL = exports.JUPUSD_VAULT = exports.JUPUSD_RATE_MODEL = exports.JUPUSD_SUPPLY_POS_ON_LIQ = exports.JUPUSD_RESERVES_LIQUIDITY = exports.JUPUSD_FTOKEN_MINT = exports.JUPUSD_LENDING = exports.JUP_LEND_EARN_PROGRAM = void 0;
|
|
27
|
+
exports.computeExchangeRate = computeExchangeRate;
|
|
28
|
+
exports.computeFTokenValue = computeFTokenValue;
|
|
29
|
+
exports.computeEarnApr = computeEarnApr;
|
|
30
|
+
exports.fetchEarnPosition = fetchEarnPosition;
|
|
31
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
32
|
+
const buffer_1 = require("../common/buffer");
|
|
33
|
+
const jupiter_lend_1 = require("../elemental-lend/jupiter-lend");
|
|
34
|
+
const constants_1 = require("../elemental-lend/constants");
|
|
35
|
+
Object.defineProperty(exports, "JUP_LEND_EARN_PROGRAM", { enumerable: true, get: function () { return constants_1.JUP_LEND_EARN_PROGRAM; } });
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// JupUSD Earn Pool — Static Accounts
|
|
38
|
+
// ----------------------------------------------------------------------------
|
|
39
|
+
// All pool addresses are imported from `elemental-lend/jupiter-lend.ts` so
|
|
40
|
+
// there is exactly one canonical definition. The named re-exports below are
|
|
41
|
+
// preserved for backwards compatibility with any external consumers.
|
|
42
|
+
// ============================================================================
|
|
43
|
+
exports.JUPUSD_LENDING = jupiter_lend_1.JUPUSD_POOL.lending;
|
|
44
|
+
exports.JUPUSD_FTOKEN_MINT = jupiter_lend_1.JUPUSD_POOL.fTokenMint;
|
|
45
|
+
exports.JUPUSD_RESERVES_LIQUIDITY = jupiter_lend_1.JUPUSD_POOL.tokenReservesLiquidity;
|
|
46
|
+
exports.JUPUSD_SUPPLY_POS_ON_LIQ = jupiter_lend_1.JUPUSD_POOL.supplyPositionOnLiquidity;
|
|
47
|
+
exports.JUPUSD_RATE_MODEL = jupiter_lend_1.JUPUSD_POOL.rateModel;
|
|
48
|
+
exports.JUPUSD_VAULT = jupiter_lend_1.JUPUSD_POOL.vault;
|
|
49
|
+
exports.JUPUSD_REWARDS_RATE_MODEL = jupiter_lend_1.JUPUSD_POOL.rewardsRateModel;
|
|
50
|
+
exports.JUPUSD_LENDING_ADMIN = jupiter_lend_1.LENDING_ADMIN;
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Exchange Rate / APR Computation
|
|
53
|
+
// ============================================================================
|
|
54
|
+
const EXCHANGE_PRICES_PRECISION = 1000000000000n; // 1e12
|
|
55
|
+
const SECONDS_PER_YEAR = 31536000;
|
|
56
|
+
/**
|
|
57
|
+
* Read the earn exchange rate from lending account + rewards model.
|
|
58
|
+
* Returns the rate scaled to 1e12.
|
|
59
|
+
*
|
|
60
|
+
* Jupiter Lend Earn lending account layout (relevant fields):
|
|
61
|
+
* [115..123] baseExchangePrice u64 (1e12 precision)
|
|
62
|
+
* [123..131] lastUpdate u64 (unix seconds)
|
|
63
|
+
*
|
|
64
|
+
* Jupiter Lend rewards rate model layout (relevant fields):
|
|
65
|
+
* [ 56.. 64] startTime u64 (unix seconds)
|
|
66
|
+
* [ 64.. 72] yearlyReward u64 (rewards distributed per year)
|
|
67
|
+
*/
|
|
68
|
+
function computeExchangeRate(lendingData, rewardsModelData, fTokenTotalSupply, currentTimestamp) {
|
|
69
|
+
if (lendingData.length < 131)
|
|
70
|
+
throw new Error("Lending data too short");
|
|
71
|
+
const baseRate = (0, buffer_1.readU64)(lendingData, 115).toNumber();
|
|
72
|
+
const lastUpdate = (0, buffer_1.readU64)(lendingData, 123).toNumber();
|
|
73
|
+
if (rewardsModelData.length < 72)
|
|
74
|
+
return BigInt(baseRate);
|
|
75
|
+
const startTime = (0, buffer_1.readU64)(rewardsModelData, 56).toNumber();
|
|
76
|
+
const yearlyReward = (0, buffer_1.readU64)(rewardsModelData, 64).toNumber();
|
|
77
|
+
if (yearlyReward === 0 || fTokenTotalSupply.isZero())
|
|
78
|
+
return BigInt(baseRate);
|
|
79
|
+
// Compute time-accrued rewards since last update
|
|
80
|
+
const elapsed = Math.max(0, currentTimestamp - Math.max(lastUpdate, startTime));
|
|
81
|
+
const totalAssets = Number((BigInt(fTokenTotalSupply.toString()) * BigInt(baseRate)) / EXCHANGE_PRICES_PRECISION);
|
|
82
|
+
if (totalAssets === 0)
|
|
83
|
+
return BigInt(baseRate);
|
|
84
|
+
// rewards_return = yearly_reward * elapsed / SECONDS_PER_YEAR / total_assets
|
|
85
|
+
// new_rate = base_rate + base_rate * rewards_return / 1e14
|
|
86
|
+
const rewardAmount = (yearlyReward * elapsed) / SECONDS_PER_YEAR;
|
|
87
|
+
const rewardsReturn = Math.floor((rewardAmount * 1e14) / totalAssets);
|
|
88
|
+
const newRate = BigInt(baseRate) + (BigInt(baseRate) * BigInt(rewardsReturn)) / 100000000000000n;
|
|
89
|
+
return newRate;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Compute the value of fTokens in JupUSD (native 6-decimal).
|
|
93
|
+
*/
|
|
94
|
+
function computeFTokenValue(fTokenBalance, exchangeRate) {
|
|
95
|
+
const value = (BigInt(fTokenBalance.toString()) * exchangeRate) / EXCHANGE_PRICES_PRECISION;
|
|
96
|
+
return new bn_js_1.default(value.toString());
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Compute earn APR breakdown: base lending + rewards.
|
|
100
|
+
*
|
|
101
|
+
* Total APR is derived by projecting the exchange rate 1 year forward
|
|
102
|
+
* (captures both lending yield and rewards). Rewards APR is isolated
|
|
103
|
+
* from yearly_reward / total_assets. Base = total - rewards.
|
|
104
|
+
*/
|
|
105
|
+
/**
|
|
106
|
+
* Compute earn APR breakdown: base lending + rewards.
|
|
107
|
+
*
|
|
108
|
+
* Reads the liquidity pool's supply rate from the liquidity account,
|
|
109
|
+
* and the rewards rate from the rewards model. Requires the liquidity
|
|
110
|
+
* account data as an additional parameter.
|
|
111
|
+
*
|
|
112
|
+
* @param rewardsModelData - Rewards rate model account data
|
|
113
|
+
* @param fTokenTotalSupply - fToken total supply (from mint)
|
|
114
|
+
* @param tokenExchangePrice - From lending account offset 115
|
|
115
|
+
* @param liquiditySupplyRate - Supply rate from liquidity pool (pass 0 if unknown)
|
|
116
|
+
*/
|
|
117
|
+
function computeEarnApr(rewardsModelData, fTokenTotalSupply, tokenExchangePrice, liquiditySupplyRate) {
|
|
118
|
+
const zero = { lendingApr: 0, rewardsApr: 0, totalApr: 0 };
|
|
119
|
+
if (rewardsModelData.length < 72)
|
|
120
|
+
return zero;
|
|
121
|
+
if (fTokenTotalSupply.isZero() || tokenExchangePrice === 0n)
|
|
122
|
+
return zero;
|
|
123
|
+
// Rewards APR: yearly_reward / total_assets * 100
|
|
124
|
+
const yearlyReward = Number((0, buffer_1.readU64)(rewardsModelData, 64).toString());
|
|
125
|
+
const totalAssets = Number(BigInt(fTokenTotalSupply.toString()) * tokenExchangePrice / EXCHANGE_PRICES_PRECISION);
|
|
126
|
+
const rewardsApr = totalAssets > 0 ? (yearlyReward / totalAssets) * 100 : 0;
|
|
127
|
+
// Lending APR: from liquidity pool supply rate if provided
|
|
128
|
+
// The lend-read SDK returns supplyRate as an integer where /100 = %
|
|
129
|
+
const lendingApr = liquiditySupplyRate != null ? liquiditySupplyRate / 100 : 0;
|
|
130
|
+
return {
|
|
131
|
+
lendingApr,
|
|
132
|
+
rewardsApr,
|
|
133
|
+
totalApr: lendingApr + rewardsApr,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Fetch the earn position for a jlpd_config PDA.
|
|
138
|
+
* Returns null if no fToken ATA exists.
|
|
139
|
+
*/
|
|
140
|
+
async function fetchEarnPosition(connection, fTokenAta) {
|
|
141
|
+
const [ataInfo, lendingInfo, rewardsInfo, mintInfo] = await connection.getMultipleAccountsInfo([
|
|
142
|
+
fTokenAta,
|
|
143
|
+
exports.JUPUSD_LENDING,
|
|
144
|
+
exports.JUPUSD_REWARDS_RATE_MODEL,
|
|
145
|
+
exports.JUPUSD_FTOKEN_MINT,
|
|
146
|
+
]);
|
|
147
|
+
if (!ataInfo || !lendingInfo || !rewardsInfo || !mintInfo)
|
|
148
|
+
return null;
|
|
149
|
+
// SPL Token Account layout: [mint(0..32)][owner(32..64)][amount(64..72)]…
|
|
150
|
+
const ataData = ataInfo.data;
|
|
151
|
+
if (ataData.length < 72)
|
|
152
|
+
return null;
|
|
153
|
+
const fTokenBalance = (0, buffer_1.readU64)(ataData, 64);
|
|
154
|
+
// SPL Token Mint layout: [mintAuthority(0..36)][supply(36..44)][decimals(44..45)]…
|
|
155
|
+
const mintData = mintInfo.data;
|
|
156
|
+
const fTokenSupply = (0, buffer_1.readU64)(mintData, 36);
|
|
157
|
+
// baseExchangePrice from Jupiter Lend Earn lending account (offset 115)
|
|
158
|
+
const lendingData = lendingInfo.data;
|
|
159
|
+
const rewardsData = rewardsInfo.data;
|
|
160
|
+
const tokenExchangePrice = BigInt((0, buffer_1.readU64)(lendingData, 115).toString());
|
|
161
|
+
const now = Math.floor(Date.now() / 1000);
|
|
162
|
+
const exchangeRate = computeExchangeRate(lendingData, rewardsData, fTokenSupply, now);
|
|
163
|
+
const jupusdValue = computeFTokenValue(fTokenBalance, exchangeRate);
|
|
164
|
+
const apr = computeEarnApr(rewardsData, fTokenSupply, tokenExchangePrice);
|
|
165
|
+
return { fTokenBalance, jupusdValue, apr };
|
|
166
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live per-custody JLP price — canonical SDK port of the on-chain
|
|
3
|
+
* `jlpd-strategy/programs/jlpd-strategy/src/utils/oracle.rs::compute_live_jlp_price`
|
|
4
|
+
* (program `GXqt4ZH2UUBsLWwMNJiZMXza3q7xEGChfW8XjVRjLxr5`, mainnet). Verbatim port of
|
|
5
|
+
* `jlpd-server/src/services/live-jlp-price.ts` (itself a verified mirror of `oracle.rs`) —
|
|
6
|
+
* promoted here per the on-chain-strategy-migration plan so BOTH the strategy driver and the
|
|
7
|
+
* frontend consume ONE typed implementation instead of jlpd-server's private copy.
|
|
8
|
+
*
|
|
9
|
+
* This recomputes JLP's virtual price directly from the Jupiter Perps pool's `custodies` Vec +
|
|
10
|
+
* each custody account's own balances/debt/short state, instead of trusting the pool's stored
|
|
11
|
+
* `aumUsd` snapshot (see `readJlpPoolPrice`-style helpers in `jlp-data.ts` for that older path).
|
|
12
|
+
* Only the on-chain `settle_yield` path uses this live recompute; this module exists so a
|
|
13
|
+
* driver/frontend can predict it off-chain before submitting a tx, or simply render it.
|
|
14
|
+
*
|
|
15
|
+
* ALL arithmetic is bigint to match Rust's u128/i128 exactly (truncating division for the
|
|
16
|
+
* signed short-PnL term; ceil-division for net_debt).
|
|
17
|
+
*
|
|
18
|
+
* The custody SET, count, and order come ENTIRELY from the pool's own `custodies` Vec
|
|
19
|
+
* (`getPoolCustodyPubkeys`) — nothing about the custody list is hardcoded here. The only pinned
|
|
20
|
+
* mapping is volatile mint -> Doves feed (SOL/ETH/WBTC); an unrecognized volatile mint fails
|
|
21
|
+
* closed.
|
|
22
|
+
*/
|
|
23
|
+
import { PublicKey } from "@solana/web3.js";
|
|
24
|
+
import type { SolanaConnection } from "../common/connection";
|
|
25
|
+
/**
|
|
26
|
+
* Parse a Doves oracle price-feed account into an 8-decimal price. Mirrors
|
|
27
|
+
* `oracle.rs::read_doves_price`'s parse (price@73 u64, exponent@81 i8) minus the
|
|
28
|
+
* owner/tag/staleness checks, which the on-chain program alone enforces on ITS reads — this
|
|
29
|
+
* helper is a pure parse for off-chain prediction/rendering.
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseDovesPrice(data: Buffer): bigint;
|
|
32
|
+
/**
|
|
33
|
+
* Parse the JLP pool account's `custodies` Vec and return the custody pubkeys IN VEC ORDER.
|
|
34
|
+
* This is the sole source of truth for the custody set/count/order — nothing is hardcoded.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getPoolCustodyPubkeys(connection: SolanaConnection): Promise<PublicKey[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Live JLP price (8-dec) = Σ per-custody USD × 1e8 / jlp_supply.
|
|
39
|
+
*
|
|
40
|
+
* Mirrors `compute_live_jlp_price` exactly: reads the pool's custody Vec (order + count from
|
|
41
|
+
* the pool itself, nothing hardcoded), decodes + guards each custody, prices volatiles off
|
|
42
|
+
* Doves ([SOL, ETH, BTC]), values stables at $1, sums, requires
|
|
43
|
+
* Σtarget_ratio_bps == 10000 (layout tripwire), divides by live JLP mint supply, and clamps to
|
|
44
|
+
* [$0.50, $50].
|
|
45
|
+
*/
|
|
46
|
+
export declare function computeLiveJlpPriceUsd(connection: SolanaConnection): Promise<bigint>;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Live per-custody JLP price — canonical SDK port of the on-chain
|
|
4
|
+
* `jlpd-strategy/programs/jlpd-strategy/src/utils/oracle.rs::compute_live_jlp_price`
|
|
5
|
+
* (program `GXqt4ZH2UUBsLWwMNJiZMXza3q7xEGChfW8XjVRjLxr5`, mainnet). Verbatim port of
|
|
6
|
+
* `jlpd-server/src/services/live-jlp-price.ts` (itself a verified mirror of `oracle.rs`) —
|
|
7
|
+
* promoted here per the on-chain-strategy-migration plan so BOTH the strategy driver and the
|
|
8
|
+
* frontend consume ONE typed implementation instead of jlpd-server's private copy.
|
|
9
|
+
*
|
|
10
|
+
* This recomputes JLP's virtual price directly from the Jupiter Perps pool's `custodies` Vec +
|
|
11
|
+
* each custody account's own balances/debt/short state, instead of trusting the pool's stored
|
|
12
|
+
* `aumUsd` snapshot (see `readJlpPoolPrice`-style helpers in `jlp-data.ts` for that older path).
|
|
13
|
+
* Only the on-chain `settle_yield` path uses this live recompute; this module exists so a
|
|
14
|
+
* driver/frontend can predict it off-chain before submitting a tx, or simply render it.
|
|
15
|
+
*
|
|
16
|
+
* ALL arithmetic is bigint to match Rust's u128/i128 exactly (truncating division for the
|
|
17
|
+
* signed short-PnL term; ceil-division for net_debt).
|
|
18
|
+
*
|
|
19
|
+
* The custody SET, count, and order come ENTIRELY from the pool's own `custodies` Vec
|
|
20
|
+
* (`getPoolCustodyPubkeys`) — nothing about the custody list is hardcoded here. The only pinned
|
|
21
|
+
* mapping is volatile mint -> Doves feed (SOL/ETH/WBTC); an unrecognized volatile mint fails
|
|
22
|
+
* closed.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.parseDovesPrice = parseDovesPrice;
|
|
26
|
+
exports.getPoolCustodyPubkeys = getPoolCustodyPubkeys;
|
|
27
|
+
exports.computeLiveJlpPriceUsd = computeLiveJlpPriceUsd;
|
|
28
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
29
|
+
const constants_1 = require("./constants");
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Constants (mirrors oracle.rs's top-of-file constants + CUST_* offsets)
|
|
32
|
+
// ============================================================================
|
|
33
|
+
/** Anchor discriminator of the Jupiter Perps `Pool` account: sha256("account:Pool")[..8]. */
|
|
34
|
+
const JLP_POOL_DISCRIMINATOR = Buffer.from([0xf1, 0x9a, 0x6d, 0x04, 0x11, 0xb1, 0x6d, 0xbc]);
|
|
35
|
+
/** Jupiter Perps `Custody` Anchor discriminator: sha256("account:Custody")[..8]. */
|
|
36
|
+
const JLP_CUSTODY_DISCRIMINATOR = Buffer.from([0x01, 0xb8, 0x30, 0x51, 0x5d, 0x83, 0x3f, 0x91]);
|
|
37
|
+
/** Upper bound on the pool custody count (currently 6). Bounds the Vec walk. */
|
|
38
|
+
const MAX_JLP_CUSTODIES = 16;
|
|
39
|
+
/** Custody `targetRatioBps` must sum to exactly 100% (layout tripwire). */
|
|
40
|
+
const TARGET_RATIO_BPS_SUM = 10000n;
|
|
41
|
+
/** Hardcoded stablecoin price: $1 USD with 8 decimals. */
|
|
42
|
+
const STABLECOIN_PRICE_USD = 100000000n;
|
|
43
|
+
/** on-chain `debt`/`bli` are scaled by 1e9. */
|
|
44
|
+
const DEBT_DIVISOR = 1000000000n;
|
|
45
|
+
/** Price clamp: [$0.50, $50] (8-dec). Out of range → fail closed. */
|
|
46
|
+
const MIN_JLP_PRICE = 50000000n;
|
|
47
|
+
const MAX_JLP_PRICE = 5000000000n;
|
|
48
|
+
// Jupiter Perps `Custody` field offsets (mirrors oracle.rs's CUST_* constants).
|
|
49
|
+
const CUST_POOL = 8; // Pubkey — must == JLP_POOL_ACCOUNT
|
|
50
|
+
const CUST_MINT = 40; // Pubkey
|
|
51
|
+
const CUST_DECIMALS = 104; // u8
|
|
52
|
+
const CUST_IS_STABLE = 105; // bool
|
|
53
|
+
const CUST_TARGET_RATIO_BPS = 206; // u64
|
|
54
|
+
const CUST_OWNED = 222; // u64 (token native)
|
|
55
|
+
const CUST_LOCKED = 230; // u64
|
|
56
|
+
const CUST_GUARANTEED_USD = 238; // u64 (USD 1e6)
|
|
57
|
+
const CUST_GLOBAL_SHORT_SIZES = 246; // u64 (USD 1e6)
|
|
58
|
+
const CUST_GLOBAL_SHORT_AVG_PX = 254; // u64 (USD 1e6)
|
|
59
|
+
const CUST_DEBT = 1004; // u128
|
|
60
|
+
const CUST_BLI = 1020; // u128 (borrowLendInterestsAccrued)
|
|
61
|
+
const CUST_MIN_LEN = 1036; // must cover through BLI (u128 @ 1020..1036)
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Binary parsing helpers
|
|
64
|
+
// ============================================================================
|
|
65
|
+
function readU128LE(buf, offset) {
|
|
66
|
+
let res = 0n;
|
|
67
|
+
for (let i = 0; i < 16; i++) {
|
|
68
|
+
res |= BigInt(buf[offset + i] ?? 0) << BigInt(8 * i);
|
|
69
|
+
}
|
|
70
|
+
return res;
|
|
71
|
+
}
|
|
72
|
+
function readPubkeyAt(buf, offset) {
|
|
73
|
+
return new web3_js_1.PublicKey(buf.subarray(offset, offset + 32));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Parse a Doves oracle price-feed account into an 8-decimal price. Mirrors
|
|
77
|
+
* `oracle.rs::read_doves_price`'s parse (price@73 u64, exponent@81 i8) minus the
|
|
78
|
+
* owner/tag/staleness checks, which the on-chain program alone enforces on ITS reads — this
|
|
79
|
+
* helper is a pure parse for off-chain prediction/rendering.
|
|
80
|
+
*/
|
|
81
|
+
function parseDovesPrice(data) {
|
|
82
|
+
if (data.length < 91)
|
|
83
|
+
throw new Error("live-jlp-price: Doves oracle data too short");
|
|
84
|
+
const rawPrice = data.readBigUInt64LE(73);
|
|
85
|
+
const exponent = (data[81] << 24) >> 24; // sign-extend i8
|
|
86
|
+
const expDiff = 8 + exponent;
|
|
87
|
+
return expDiff >= 0
|
|
88
|
+
? rawPrice * 10n ** BigInt(expDiff)
|
|
89
|
+
: rawPrice / 10n ** BigInt(-expDiff);
|
|
90
|
+
}
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// Pool custodies Vec parse
|
|
93
|
+
// ============================================================================
|
|
94
|
+
/**
|
|
95
|
+
* Parse the JLP pool account's `custodies` Vec and return the custody pubkeys IN VEC ORDER.
|
|
96
|
+
* This is the sole source of truth for the custody set/count/order — nothing is hardcoded.
|
|
97
|
+
*/
|
|
98
|
+
async function getPoolCustodyPubkeys(connection) {
|
|
99
|
+
const poolInfo = await connection.getAccountInfo(constants_1.JLP_POOL_ACCOUNT);
|
|
100
|
+
if (!poolInfo)
|
|
101
|
+
throw new Error("live-jlp-price: JLP pool account not found");
|
|
102
|
+
if (!poolInfo.owner.equals(constants_1.JUPITER_PERPS_PROGRAM)) {
|
|
103
|
+
throw new Error("live-jlp-price: JLP pool account owned by unexpected program");
|
|
104
|
+
}
|
|
105
|
+
const data = poolInfo.data;
|
|
106
|
+
if (data.length < 12)
|
|
107
|
+
throw new Error("live-jlp-price: JLP pool account too short");
|
|
108
|
+
if (!data.subarray(0, 8).equals(JLP_POOL_DISCRIMINATOR)) {
|
|
109
|
+
throw new Error("live-jlp-price: JLP pool discriminator mismatch (layout changed?)");
|
|
110
|
+
}
|
|
111
|
+
const nameLen = data.readUInt32LE(8);
|
|
112
|
+
if (nameLen > 64)
|
|
113
|
+
throw new Error(`live-jlp-price: JLP pool name length implausible: ${nameLen}`);
|
|
114
|
+
const countOff = 12 + nameLen;
|
|
115
|
+
if (data.length < countOff + 4)
|
|
116
|
+
throw new Error("live-jlp-price: JLP pool account too short (custodies count)");
|
|
117
|
+
const count = data.readUInt32LE(countOff);
|
|
118
|
+
if (count < 1 || count > MAX_JLP_CUSTODIES) {
|
|
119
|
+
throw new Error(`live-jlp-price: JLP pool custody count implausible: ${count}`);
|
|
120
|
+
}
|
|
121
|
+
const pkStart = countOff + 4;
|
|
122
|
+
if (data.length < pkStart + count * 32) {
|
|
123
|
+
throw new Error("live-jlp-price: JLP pool account too short (custodies pubkeys)");
|
|
124
|
+
}
|
|
125
|
+
const pubkeys = [];
|
|
126
|
+
for (let i = 0; i < count; i++) {
|
|
127
|
+
pubkeys.push(readPubkeyAt(data, pkStart + i * 32));
|
|
128
|
+
}
|
|
129
|
+
return pubkeys;
|
|
130
|
+
}
|
|
131
|
+
/** Decode + guard one custody account's raw bytes. Throws on any binding mismatch. */
|
|
132
|
+
function decodeCustodyBytes(data, owner) {
|
|
133
|
+
if (!owner.equals(constants_1.JUPITER_PERPS_PROGRAM)) {
|
|
134
|
+
throw new Error("live-jlp-price: custody account owned by unexpected program");
|
|
135
|
+
}
|
|
136
|
+
if (data.length < CUST_MIN_LEN)
|
|
137
|
+
throw new Error("live-jlp-price: custody account too short");
|
|
138
|
+
if (!data.subarray(0, 8).equals(JLP_CUSTODY_DISCRIMINATOR)) {
|
|
139
|
+
throw new Error("live-jlp-price: custody discriminator mismatch (layout changed?)");
|
|
140
|
+
}
|
|
141
|
+
if (!readPubkeyAt(data, CUST_POOL).equals(constants_1.JLP_POOL_ACCOUNT)) {
|
|
142
|
+
throw new Error("live-jlp-price: custody pool binding mismatch");
|
|
143
|
+
}
|
|
144
|
+
const debt = readU128LE(data, CUST_DEBT);
|
|
145
|
+
const bli = readU128LE(data, CUST_BLI);
|
|
146
|
+
// net_debt = ceil((debt - bli) / 1e9) — matches Jupiter's div_ceil (Rust saturating_sub + ceil-div).
|
|
147
|
+
const satSub = debt > bli ? debt - bli : 0n;
|
|
148
|
+
const netDebt = (satSub + DEBT_DIVISOR - 1n) / DEBT_DIVISOR;
|
|
149
|
+
return {
|
|
150
|
+
isStable: data[CUST_IS_STABLE] !== 0,
|
|
151
|
+
decimals: data[CUST_DECIMALS],
|
|
152
|
+
mint: readPubkeyAt(data, CUST_MINT),
|
|
153
|
+
owned: data.readBigUInt64LE(CUST_OWNED),
|
|
154
|
+
locked: data.readBigUInt64LE(CUST_LOCKED),
|
|
155
|
+
guaranteedUsd: data.readBigUInt64LE(CUST_GUARANTEED_USD),
|
|
156
|
+
shortSizes: data.readBigUInt64LE(CUST_GLOBAL_SHORT_SIZES),
|
|
157
|
+
shortAvgPx: data.readBigUInt64LE(CUST_GLOBAL_SHORT_AVG_PX),
|
|
158
|
+
netDebt,
|
|
159
|
+
targetRatioBps: data.readBigUInt64LE(CUST_TARGET_RATIO_BPS),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/** amount * price / 10^(decimals + 8 - 6), or amount * price * 10^-(...) if negative exponent. */
|
|
163
|
+
function baseToUsdU128(amount, price, decimals) {
|
|
164
|
+
if (amount === 0n || price === 0n)
|
|
165
|
+
return 0n;
|
|
166
|
+
const num = amount * price;
|
|
167
|
+
const exponent = decimals + 8 - 6; // ORACLE_PRICE_DECIMALS - USD_DECIMALS
|
|
168
|
+
if (exponent >= 0) {
|
|
169
|
+
return num / 10n ** BigInt(exponent);
|
|
170
|
+
}
|
|
171
|
+
return num * 10n ** BigInt(-exponent);
|
|
172
|
+
}
|
|
173
|
+
/** Map a VOLATILE custody's mint to its `vol_prices` index ([SOL, ETH, BTC]). Unknown volatile → throw. */
|
|
174
|
+
function volatileDovesIndex(mint) {
|
|
175
|
+
if (mint.equals(constants_1.MINT_WSOL))
|
|
176
|
+
return 0;
|
|
177
|
+
if (mint.equals(constants_1.MINT_WETH))
|
|
178
|
+
return 1;
|
|
179
|
+
if (mint.equals(constants_1.MINT_WBTC))
|
|
180
|
+
return 2;
|
|
181
|
+
throw new Error(`live-jlp-price: unrecognized volatile custody mint ${mint.toBase58()} (no oracle feed)`);
|
|
182
|
+
}
|
|
183
|
+
/** Per-custody USD (6-dec). `price` is the volatile Doves price (8-dec); ignored for stables. */
|
|
184
|
+
function custodyUsd(c, price) {
|
|
185
|
+
const net = c.owned + c.netDebt;
|
|
186
|
+
if (c.isStable) {
|
|
187
|
+
// Stable: (owned + net_debt) * $1. No locked / guaranteed / short.
|
|
188
|
+
return baseToUsdU128(net, STABLECOIN_PRICE_USD, c.decimals);
|
|
189
|
+
}
|
|
190
|
+
// Volatile: max( spot + guaranteedUsd + signedShortPnL, 0 )
|
|
191
|
+
const spot = net <= c.locked ? 0n : baseToUsdU128(net - c.locked, price, c.decimals);
|
|
192
|
+
// shortPnL = shortSizes * (price/100 - avgShortPx) / avgShortPx — SIGNED, USD 1e6.
|
|
193
|
+
// Doves price is 8-dec; /100 rescales to the 6-dec avgShortPx basis.
|
|
194
|
+
let short = 0n;
|
|
195
|
+
if (c.shortSizes > 0n && c.shortAvgPx > 0n) {
|
|
196
|
+
const px1e6 = price / 100n;
|
|
197
|
+
const diff = px1e6 - c.shortAvgPx;
|
|
198
|
+
short = (c.shortSizes * diff) / c.shortAvgPx;
|
|
199
|
+
}
|
|
200
|
+
const total = spot + c.guaranteedUsd + short;
|
|
201
|
+
return total > 0n ? total : 0n;
|
|
202
|
+
}
|
|
203
|
+
// ============================================================================
|
|
204
|
+
// computeLiveJlpPriceUsd — the full per-custody fold
|
|
205
|
+
// ============================================================================
|
|
206
|
+
/**
|
|
207
|
+
* Live JLP price (8-dec) = Σ per-custody USD × 1e8 / jlp_supply.
|
|
208
|
+
*
|
|
209
|
+
* Mirrors `compute_live_jlp_price` exactly: reads the pool's custody Vec (order + count from
|
|
210
|
+
* the pool itself, nothing hardcoded), decodes + guards each custody, prices volatiles off
|
|
211
|
+
* Doves ([SOL, ETH, BTC]), values stables at $1, sums, requires
|
|
212
|
+
* Σtarget_ratio_bps == 10000 (layout tripwire), divides by live JLP mint supply, and clamps to
|
|
213
|
+
* [$0.50, $50].
|
|
214
|
+
*/
|
|
215
|
+
async function computeLiveJlpPriceUsd(connection) {
|
|
216
|
+
const custodyPks = await getPoolCustodyPubkeys(connection);
|
|
217
|
+
const keys = [...custodyPks, constants_1.DOVES_SOL_USD, constants_1.DOVES_ETH_USD, constants_1.DOVES_BTC_USD, constants_1.JLP_MINT];
|
|
218
|
+
const infos = await connection.getMultipleAccountsInfo(keys);
|
|
219
|
+
const n = custodyPks.length;
|
|
220
|
+
const dovesSolInfo = infos[n];
|
|
221
|
+
const dovesEthInfo = infos[n + 1];
|
|
222
|
+
const dovesBtcInfo = infos[n + 2];
|
|
223
|
+
const mintInfo = infos[n + 3];
|
|
224
|
+
if (!dovesSolInfo)
|
|
225
|
+
throw new Error("live-jlp-price: Doves SOL/USD account not found");
|
|
226
|
+
if (!dovesEthInfo)
|
|
227
|
+
throw new Error("live-jlp-price: Doves ETH/USD account not found");
|
|
228
|
+
if (!dovesBtcInfo)
|
|
229
|
+
throw new Error("live-jlp-price: Doves BTC/USD account not found");
|
|
230
|
+
if (!mintInfo)
|
|
231
|
+
throw new Error("live-jlp-price: JLP mint account not found");
|
|
232
|
+
const solPrice = parseDovesPrice(dovesSolInfo.data);
|
|
233
|
+
const ethPrice = parseDovesPrice(dovesEthInfo.data);
|
|
234
|
+
const btcPrice = parseDovesPrice(dovesBtcInfo.data);
|
|
235
|
+
if (solPrice <= 0n)
|
|
236
|
+
throw new Error("live-jlp-price: Doves SOL/USD price non-positive");
|
|
237
|
+
if (ethPrice <= 0n)
|
|
238
|
+
throw new Error("live-jlp-price: Doves ETH/USD price non-positive");
|
|
239
|
+
if (btcPrice <= 0n)
|
|
240
|
+
throw new Error("live-jlp-price: Doves BTC/USD price non-positive");
|
|
241
|
+
const volPrices = [solPrice, ethPrice, btcPrice];
|
|
242
|
+
let aum = 0n;
|
|
243
|
+
let targetSum = 0n;
|
|
244
|
+
for (let i = 0; i < n; i++) {
|
|
245
|
+
const info = infos[i];
|
|
246
|
+
if (!info)
|
|
247
|
+
throw new Error(`live-jlp-price: custody account ${custodyPks[i].toBase58()} not found`);
|
|
248
|
+
const vals = decodeCustodyBytes(info.data, info.owner);
|
|
249
|
+
targetSum += vals.targetRatioBps;
|
|
250
|
+
const price = vals.isStable ? 0n : volPrices[volatileDovesIndex(vals.mint)];
|
|
251
|
+
aum += custodyUsd(vals, price);
|
|
252
|
+
}
|
|
253
|
+
if (targetSum !== TARGET_RATIO_BPS_SUM) {
|
|
254
|
+
throw new Error(`live-jlp-price: Σtarget_ratio_bps == ${targetSum}, expected 10000 (layout tripwire)`);
|
|
255
|
+
}
|
|
256
|
+
const mintData = mintInfo.data;
|
|
257
|
+
if (mintData.length < 44)
|
|
258
|
+
throw new Error("live-jlp-price: JLP mint account too short");
|
|
259
|
+
const supply = mintData.readBigUInt64LE(36);
|
|
260
|
+
if (supply <= 0n)
|
|
261
|
+
throw new Error("live-jlp-price: JLP mint supply is zero");
|
|
262
|
+
const price = (aum * 100000000n) / supply;
|
|
263
|
+
if (price < MIN_JLP_PRICE || price > MAX_JLP_PRICE) {
|
|
264
|
+
throw new Error(`live-jlp-price: computed price ${price} outside [$0.50, $50] clamp`);
|
|
265
|
+
}
|
|
266
|
+
return price;
|
|
267
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
export declare function findJlpdConfigPda(programId?: PublicKey): [PublicKey, number];
|
|
3
|
+
/**
|
|
4
|
+
* Derive the per-JlpdConfig `ManagerRole` PDA for JLPD Strategy.
|
|
5
|
+
* Seeds: `["manager", config, manager]`.
|
|
6
|
+
*
|
|
7
|
+
* Note the per-program prefix on the name: each Elemental program has its
|
|
8
|
+
* own `ManagerRole` PDA scoped to a different anchor account (`p-stv-core`
|
|
9
|
+
* → STV, `elemental-lend` → strategy_state).
|
|
10
|
+
*/
|
|
11
|
+
export declare function findJlpdManagerRolePda(config: PublicKey, manager: PublicKey, programId?: PublicKey): [PublicKey, number];
|
|
12
|
+
export declare function findStrategyStatePda(baseMint: PublicKey, programId?: PublicKey): [PublicKey, number];
|
|
13
|
+
export declare function findStvPositionPda(stv: PublicKey, programId?: PublicKey): [PublicKey, number];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findJlpdConfigPda = findJlpdConfigPda;
|
|
4
|
+
exports.findJlpdManagerRolePda = findJlpdManagerRolePda;
|
|
5
|
+
exports.findStrategyStatePda = findStrategyStatePda;
|
|
6
|
+
exports.findStvPositionPda = findStvPositionPda;
|
|
7
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
function findJlpdConfigPda(programId = constants_1.PROGRAM_ID) {
|
|
10
|
+
return web3_js_1.PublicKey.findProgramAddressSync([constants_1.CONFIG_SEED], programId);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Derive the per-JlpdConfig `ManagerRole` PDA for JLPD Strategy.
|
|
14
|
+
* Seeds: `["manager", config, manager]`.
|
|
15
|
+
*
|
|
16
|
+
* Note the per-program prefix on the name: each Elemental program has its
|
|
17
|
+
* own `ManagerRole` PDA scoped to a different anchor account (`p-stv-core`
|
|
18
|
+
* → STV, `elemental-lend` → strategy_state).
|
|
19
|
+
*/
|
|
20
|
+
function findJlpdManagerRolePda(config, manager, programId = constants_1.PROGRAM_ID) {
|
|
21
|
+
return web3_js_1.PublicKey.findProgramAddressSync([constants_1.MANAGER_SEED, config.toBuffer(), manager.toBuffer()], programId);
|
|
22
|
+
}
|
|
23
|
+
function findStrategyStatePda(baseMint, programId = constants_1.PROGRAM_ID) {
|
|
24
|
+
return web3_js_1.PublicKey.findProgramAddressSync([constants_1.STRATEGY_STATE_SEED, baseMint.toBuffer()], programId);
|
|
25
|
+
}
|
|
26
|
+
function findStvPositionPda(stv, programId = constants_1.PROGRAM_ID) {
|
|
27
|
+
return web3_js_1.PublicKey.findProgramAddressSync([constants_1.POSITION_SEED, stv.toBuffer()], programId);
|
|
28
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PublicKey, TransactionInstruction, AccountMeta } from "@solana/web3.js";
|
|
2
|
+
/** Arguments accepted by `createSettleYieldIx`. */
|
|
3
|
+
export interface CreateSettleYieldIxArgs {
|
|
4
|
+
manager: PublicKey;
|
|
5
|
+
/** 5 base asset mints in order: [BTC, ETH, SOL, USDC, JupUSD]. */
|
|
6
|
+
baseAssetMints: [PublicKey, PublicKey, PublicKey, PublicKey, PublicKey];
|
|
7
|
+
jlpMint?: PublicKey;
|
|
8
|
+
tokenProgram?: PublicKey;
|
|
9
|
+
programId?: PublicKey;
|
|
10
|
+
/**
|
|
11
|
+
* Hedge block accounts (position/vault_state pairs per enabled hedge slot,
|
|
12
|
+
* plus the manifest + earn block), appended after the 15 fixed accounts and
|
|
13
|
+
* BEFORE `custodyAccounts`. Defaults to `[]` -- for now callers pass nothing
|
|
14
|
+
* while the hedge is disabled.
|
|
15
|
+
*/
|
|
16
|
+
hedgeAccounts?: AccountMeta[];
|
|
17
|
+
/**
|
|
18
|
+
* JLP pool custody accounts, in the pool `custodies` Vec order (6 today).
|
|
19
|
+
* REQUIRED on mainnet even when the hedge is off -- consumed by
|
|
20
|
+
* `compute_live_jlp_price`. Appended last, after `hedgeAccounts`.
|
|
21
|
+
*/
|
|
22
|
+
custodyAccounts: PublicKey[];
|
|
23
|
+
/**
|
|
24
|
+
* Doves price-feed accounts for BTC/ETH/SOL. These MUST equal the on-chain
|
|
25
|
+
* `strategy_state.price_oracle` of each respective strategy (the program now
|
|
26
|
+
* validates the passed oracle against the stored feed). To stay rotation-proof,
|
|
27
|
+
* read each strategy's `priceOracle` from chain and pass it here. If omitted,
|
|
28
|
+
* falls back to the `DOVES_*_USD` reference constants (correct only while they
|
|
29
|
+
* match the backfilled on-chain value).
|
|
30
|
+
*/
|
|
31
|
+
priceOracleBtc?: PublicKey;
|
|
32
|
+
priceOracleEth?: PublicKey;
|
|
33
|
+
priceOracleSol?: PublicKey;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build a `settle_yield` instruction with automatic PDA derivation.
|
|
37
|
+
*
|
|
38
|
+
* Requires the 5 base asset mints in order: [BTC, ETH, SOL, USDC, JupUSD].
|
|
39
|
+
* These must match the `base_asset_mints` array on the JlpdConfig account.
|
|
40
|
+
*
|
|
41
|
+
* Naming follows the SDK convention: low-level instruction builders are named
|
|
42
|
+
* `create*Ix` (this is the canonical name); high-level transaction wrappers
|
|
43
|
+
* (if any) are named `build*Transaction`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createSettleYieldIx(args: CreateSettleYieldIxArgs): TransactionInstruction;
|