@0dotxyz/p0-ts-sdk 2.8.2 → 2.8.3-alpha.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.
package/dist/index.cjs CHANGED
@@ -74918,6 +74918,231 @@ async function computeSmartCrank({
74918
74918
  isCrankable: true
74919
74919
  });
74920
74920
  }
74921
+ new web3_js.PublicKey("MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD");
74922
+ var MARINADE_STATE_DISCRIMINATOR = Buffer.from([216, 146, 107, 94, 104, 75, 182, 177]);
74923
+ var DELAYED_UNSTAKE_COOLING_DOWN_OFFSET = 226;
74924
+ var TOTAL_ACTIVE_BALANCE_OFFSET = 376;
74925
+ var AVAILABLE_RESERVE_BALANCE_OFFSET = 496;
74926
+ var MSOL_SUPPLY_OFFSET = 504;
74927
+ var CIRCULATING_TICKET_BALANCE_OFFSET = 528;
74928
+ var EMERGENCY_COOLING_DOWN_OFFSET = 568;
74929
+ var MARINADE_STATE_MIN_SIZE = EMERGENCY_COOLING_DOWN_OFFSET + 8;
74930
+ var U64_MAX = (1n << 64n) - 1n;
74931
+ var MAX_MSOL_SOL_RATE = 3;
74932
+ function decodeMarinadeState(data) {
74933
+ if (data.length < MARINADE_STATE_MIN_SIZE) {
74934
+ throw new Error(`Invalid Marinade State account size: ${data.length}`);
74935
+ }
74936
+ if (!data.subarray(0, 8).equals(MARINADE_STATE_DISCRIMINATOR)) {
74937
+ throw new Error("Invalid Marinade State discriminator");
74938
+ }
74939
+ const delayedUnstakeCoolingDown = data.readBigUInt64LE(DELAYED_UNSTAKE_COOLING_DOWN_OFFSET);
74940
+ const totalActiveBalance = data.readBigUInt64LE(TOTAL_ACTIVE_BALANCE_OFFSET);
74941
+ const availableReserveBalance = data.readBigUInt64LE(AVAILABLE_RESERVE_BALANCE_OFFSET);
74942
+ const msolSupply = data.readBigUInt64LE(MSOL_SUPPLY_OFFSET);
74943
+ const circulatingTicketBalance = data.readBigUInt64LE(CIRCULATING_TICKET_BALANCE_OFFSET);
74944
+ const emergencyCoolingDown = data.readBigUInt64LE(EMERGENCY_COOLING_DOWN_OFFSET);
74945
+ if (msolSupply === 0n) {
74946
+ throw new Error("Marinade State has zero mSOL supply");
74947
+ }
74948
+ const underControl = totalActiveBalance + delayedUnstakeCoolingDown + emergencyCoolingDown + availableReserveBalance;
74949
+ if (underControl > U64_MAX) {
74950
+ throw new Error("Marinade virtual staked balance overflow");
74951
+ }
74952
+ const totalVirtualStakedLamports = underControl > circulatingTicketBalance ? underControl - circulatingTicketBalance : 0n;
74953
+ const msolPrice = new BigNumber3__default.default(totalVirtualStakedLamports.toString()).div(msolSupply.toString());
74954
+ if (!msolPrice.gt(0) || msolPrice.gte(MAX_MSOL_SOL_RATE)) {
74955
+ throw new Error(`Marinade mSOL/SOL rate out of bounds: ${msolPrice.toString()}`);
74956
+ }
74957
+ return { msolPrice };
74958
+ }
74959
+ new web3_js.PublicKey(
74960
+ "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy"
74961
+ );
74962
+ new web3_js.PublicKey(
74963
+ "SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY"
74964
+ );
74965
+ new web3_js.PublicKey(
74966
+ "SPMBzsVUuoHA4Jm6KunbsotaahvVikZs1JyTW6iJvbn"
74967
+ );
74968
+ var ACCOUNT_TYPE_STAKE_POOL = 1;
74969
+ var TOTAL_LAMPORTS_OFFSET = 258;
74970
+ var POOL_TOKEN_SUPPLY_OFFSET = 266;
74971
+ var LAST_UPDATE_EPOCH_OFFSET = 274;
74972
+ var MAX_LST_SOL_RATE = 3;
74973
+ function decodeStakePool(data) {
74974
+ if (data.length < LAST_UPDATE_EPOCH_OFFSET + 8) {
74975
+ throw new Error(`Invalid StakePool account size: ${data.length}`);
74976
+ }
74977
+ if (data[0] !== ACCOUNT_TYPE_STAKE_POOL) {
74978
+ throw new Error(`Invalid StakePool account type: ${data[0]}`);
74979
+ }
74980
+ const totalLamports = data.readBigUInt64LE(TOTAL_LAMPORTS_OFFSET);
74981
+ const poolTokenSupply = data.readBigUInt64LE(POOL_TOKEN_SUPPLY_OFFSET);
74982
+ const lastUpdateEpoch = Number(data.readBigUInt64LE(LAST_UPDATE_EPOCH_OFFSET));
74983
+ if (poolTokenSupply === 0n) {
74984
+ throw new Error("StakePool has zero token supply");
74985
+ }
74986
+ const exchangeRate = new BigNumber3__default.default(totalLamports.toString()).div(
74987
+ new BigNumber3__default.default(poolTokenSupply.toString())
74988
+ );
74989
+ if (!exchangeRate.gt(0) || exchangeRate.gte(MAX_LST_SOL_RATE)) {
74990
+ throw new Error(`StakePool LST/SOL rate out of bounds: ${exchangeRate.toString()}`);
74991
+ }
74992
+ return {
74993
+ totalLamports,
74994
+ poolTokenSupply,
74995
+ lastUpdateEpoch,
74996
+ exchangeRate
74997
+ };
74998
+ }
74999
+
75000
+ // src/services/price/utils/multiplier-data.utils.ts
75001
+ var PT_MAX_MATURITY_HORIZON_SECONDS = 5 * 365 * 24 * 60 * 60;
75002
+ var MAX_SY_EXCHANGE_RATE = new BigNumber3__default.default("18446744073709551615").div(1e12);
75003
+ var MAX_STAKE_POOL_EPOCH_LAG = 1;
75004
+ function multiplierAccountKey(bank) {
75005
+ switch (bank.config.oracleSetup) {
75006
+ case "PythMSOL" /* PythMSOL */:
75007
+ case "PythLST" /* PythLST */:
75008
+ case "PTPyth" /* PTPyth */:
75009
+ return bank.config.oracleKeys[1];
75010
+ case "KaminoMSOL" /* KaminoMSOL */:
75011
+ case "JuplendMSOL" /* JuplendMSOL */:
75012
+ case "KaminoLST" /* KaminoLST */:
75013
+ case "JuplendLST" /* JuplendLST */:
75014
+ return bank.config.oracleKeys[2];
75015
+ case "PTFixed" /* PTFixed */:
75016
+ return bank.config.oracleKeys[0];
75017
+ default:
75018
+ return void 0;
75019
+ }
75020
+ }
75021
+ function getOracleMultiplierBankInput(bank) {
75022
+ const accountKey = multiplierAccountKey(bank);
75023
+ if (!accountKey) return void 0;
75024
+ const isPt = bank.config.oracleSetup === "PTPyth" /* PTPyth */ || bank.config.oracleSetup === "PTFixed" /* PTFixed */;
75025
+ return {
75026
+ bankAddress: bank.address.toBase58(),
75027
+ oracleSetup: bank.config.oracleSetup,
75028
+ multiplierAccountKey: accountKey.toBase58(),
75029
+ fixedPrice: isPt ? bank.config.fixedPrice : void 0
75030
+ };
75031
+ }
75032
+ function decodeMultiplierAccount(data) {
75033
+ try {
75034
+ const vault = decodeExponentVault(data);
75035
+ return {
75036
+ kind: "exponentVault",
75037
+ startTs: vault.startTs,
75038
+ duration: vault.duration,
75039
+ syForPt: vault.syForPt.toString(),
75040
+ ptSupply: vault.ptSupply.toString(),
75041
+ lastSeenSyExchangeRate: vault.lastSeenSyExchangeRate.toString(),
75042
+ allTimeHighSyExchangeRate: vault.allTimeHighSyExchangeRate.toString()
75043
+ };
75044
+ } catch {
75045
+ }
75046
+ try {
75047
+ return { kind: "marinade", msolPrice: decodeMarinadeState(data).msolPrice.toString() };
75048
+ } catch {
75049
+ }
75050
+ try {
75051
+ const pool = decodeStakePool(data);
75052
+ return {
75053
+ kind: "stakePool",
75054
+ exchangeRate: pool.exchangeRate.toString(),
75055
+ lastUpdateEpoch: pool.lastUpdateEpoch
75056
+ };
75057
+ } catch {
75058
+ }
75059
+ return void 0;
75060
+ }
75061
+ function computePtMultiplier(vault, startPrice, nowSeconds) {
75062
+ const maturity = vault.startTs + vault.duration;
75063
+ if (vault.duration <= 0 || maturity > nowSeconds + PT_MAX_MATURITY_HORIZON_SECONDS) {
75064
+ throw new Error("Exponent vault has an invalid maturity schedule");
75065
+ }
75066
+ if (!vault.lastSeenSyExchangeRate.gt(0) || vault.lastSeenSyExchangeRate.gt(MAX_SY_EXCHANGE_RATE)) {
75067
+ throw new Error("Exponent vault SY exchange rate out of bounds");
75068
+ }
75069
+ if (vault.ptSupply === 0n) {
75070
+ throw new Error("Exponent vault has zero PT supply");
75071
+ }
75072
+ if (vault.lastSeenSyExchangeRate.lt(vault.allTimeHighSyExchangeRate)) {
75073
+ throw new Error("Exponent vault is in emergency mode");
75074
+ }
75075
+ let expectedRate;
75076
+ if (nowSeconds <= vault.startTs) {
75077
+ expectedRate = startPrice;
75078
+ } else if (nowSeconds >= maturity) {
75079
+ expectedRate = new BigNumber3__default.default(1);
75080
+ } else {
75081
+ const progress = new BigNumber3__default.default(nowSeconds - vault.startTs).div(vault.duration);
75082
+ expectedRate = startPrice.plus(new BigNumber3__default.default(1).minus(startPrice).times(progress));
75083
+ }
75084
+ const syPerPt = new BigNumber3__default.default(vault.syForPt.toString()).div(
75085
+ new BigNumber3__default.default(vault.ptSupply.toString())
75086
+ );
75087
+ const redemptionCap = syPerPt.times(vault.lastSeenSyExchangeRate);
75088
+ return BigNumber3__default.default.min(expectedRate, redemptionCap);
75089
+ }
75090
+ function computeOracleMultiplier(input, state, ctx) {
75091
+ switch (input.oracleSetup) {
75092
+ case "PythMSOL" /* PythMSOL */:
75093
+ case "KaminoMSOL" /* KaminoMSOL */:
75094
+ case "JuplendMSOL" /* JuplendMSOL */:
75095
+ if (state.kind !== "marinade") throw new Error(`Expected Marinade state, got ${state.kind}`);
75096
+ return Number(state.msolPrice);
75097
+ case "PythLST" /* PythLST */:
75098
+ case "KaminoLST" /* KaminoLST */:
75099
+ case "JuplendLST" /* JuplendLST */:
75100
+ if (state.kind !== "stakePool") throw new Error(`Expected stake pool, got ${state.kind}`);
75101
+ if (ctx.currentEpoch - state.lastUpdateEpoch > MAX_STAKE_POOL_EPOCH_LAG) {
75102
+ throw new Error(
75103
+ `Stale stake pool (last updated epoch ${state.lastUpdateEpoch}, current ${ctx.currentEpoch})`
75104
+ );
75105
+ }
75106
+ return Number(state.exchangeRate);
75107
+ case "PTPyth" /* PTPyth */:
75108
+ case "PTFixed" /* PTFixed */:
75109
+ if (state.kind !== "exponentVault") {
75110
+ throw new Error(`Expected Exponent vault, got ${state.kind}`);
75111
+ }
75112
+ if (!input.fixedPrice) throw new Error("Missing fixedPrice for PT bank");
75113
+ return computePtMultiplier(
75114
+ {
75115
+ startTs: state.startTs,
75116
+ duration: state.duration,
75117
+ syForPt: BigInt(state.syForPt),
75118
+ ptSupply: BigInt(state.ptSupply),
75119
+ lastSeenSyExchangeRate: new BigNumber3__default.default(state.lastSeenSyExchangeRate),
75120
+ allTimeHighSyExchangeRate: new BigNumber3__default.default(state.allTimeHighSyExchangeRate)
75121
+ },
75122
+ input.fixedPrice,
75123
+ ctx.nowSeconds
75124
+ ).toNumber();
75125
+ default:
75126
+ throw new Error(`Oracle setup ${input.oracleSetup} is not multiplier-priced`);
75127
+ }
75128
+ }
75129
+ function computeOracleMultipliers(inputs, accountStates, nowSeconds = Math.floor(Date.now() / 1e3)) {
75130
+ const multiplierByBank = {};
75131
+ const ctx = { currentEpoch: accountStates.currentEpoch, nowSeconds };
75132
+ for (const input of inputs) {
75133
+ const state = accountStates.states[input.multiplierAccountKey];
75134
+ if (!state) {
75135
+ console.error(`Missing multiplier account for bank ${input.bankAddress}`);
75136
+ continue;
75137
+ }
75138
+ try {
75139
+ multiplierByBank[input.bankAddress] = computeOracleMultiplier(input, state, ctx);
75140
+ } catch (e) {
75141
+ console.error(`Failed to compute multiplier for bank ${input.bankAddress}`, e);
75142
+ }
75143
+ }
75144
+ return multiplierByBank;
75145
+ }
74921
75146
  async function makeSmartCrankSwbFeedIx(params) {
74922
75147
  const crankResult = await computeSmartCrank(params);
74923
75148
  if (crankResult.uncrankableLiabilities.length > 0) {
@@ -75244,84 +75469,6 @@ function decodeScopePriceAtIndex(data, entryIndex) {
75244
75469
  unixTimestamp: Number(unixTimestamp)
75245
75470
  };
75246
75471
  }
75247
- new web3_js.PublicKey("MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD");
75248
- var MARINADE_STATE_DISCRIMINATOR = Buffer.from([216, 146, 107, 94, 104, 75, 182, 177]);
75249
- var DELAYED_UNSTAKE_COOLING_DOWN_OFFSET = 226;
75250
- var TOTAL_ACTIVE_BALANCE_OFFSET = 376;
75251
- var AVAILABLE_RESERVE_BALANCE_OFFSET = 496;
75252
- var MSOL_SUPPLY_OFFSET = 504;
75253
- var CIRCULATING_TICKET_BALANCE_OFFSET = 528;
75254
- var EMERGENCY_COOLING_DOWN_OFFSET = 568;
75255
- var MARINADE_STATE_MIN_SIZE = EMERGENCY_COOLING_DOWN_OFFSET + 8;
75256
- var U64_MAX = (1n << 64n) - 1n;
75257
- var MAX_MSOL_SOL_RATE = 3;
75258
- function decodeMarinadeState(data) {
75259
- if (data.length < MARINADE_STATE_MIN_SIZE) {
75260
- throw new Error(`Invalid Marinade State account size: ${data.length}`);
75261
- }
75262
- if (!data.subarray(0, 8).equals(MARINADE_STATE_DISCRIMINATOR)) {
75263
- throw new Error("Invalid Marinade State discriminator");
75264
- }
75265
- const delayedUnstakeCoolingDown = data.readBigUInt64LE(DELAYED_UNSTAKE_COOLING_DOWN_OFFSET);
75266
- const totalActiveBalance = data.readBigUInt64LE(TOTAL_ACTIVE_BALANCE_OFFSET);
75267
- const availableReserveBalance = data.readBigUInt64LE(AVAILABLE_RESERVE_BALANCE_OFFSET);
75268
- const msolSupply = data.readBigUInt64LE(MSOL_SUPPLY_OFFSET);
75269
- const circulatingTicketBalance = data.readBigUInt64LE(CIRCULATING_TICKET_BALANCE_OFFSET);
75270
- const emergencyCoolingDown = data.readBigUInt64LE(EMERGENCY_COOLING_DOWN_OFFSET);
75271
- if (msolSupply === 0n) {
75272
- throw new Error("Marinade State has zero mSOL supply");
75273
- }
75274
- const underControl = totalActiveBalance + delayedUnstakeCoolingDown + emergencyCoolingDown + availableReserveBalance;
75275
- if (underControl > U64_MAX) {
75276
- throw new Error("Marinade virtual staked balance overflow");
75277
- }
75278
- const totalVirtualStakedLamports = underControl > circulatingTicketBalance ? underControl - circulatingTicketBalance : 0n;
75279
- const msolPrice = new BigNumber3__default.default(totalVirtualStakedLamports.toString()).div(msolSupply.toString());
75280
- if (!msolPrice.gt(0) || msolPrice.gte(MAX_MSOL_SOL_RATE)) {
75281
- throw new Error(`Marinade mSOL/SOL rate out of bounds: ${msolPrice.toString()}`);
75282
- }
75283
- return { msolPrice };
75284
- }
75285
- new web3_js.PublicKey(
75286
- "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy"
75287
- );
75288
- new web3_js.PublicKey(
75289
- "SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY"
75290
- );
75291
- new web3_js.PublicKey(
75292
- "SPMBzsVUuoHA4Jm6KunbsotaahvVikZs1JyTW6iJvbn"
75293
- );
75294
- var ACCOUNT_TYPE_STAKE_POOL = 1;
75295
- var TOTAL_LAMPORTS_OFFSET = 258;
75296
- var POOL_TOKEN_SUPPLY_OFFSET = 266;
75297
- var LAST_UPDATE_EPOCH_OFFSET = 274;
75298
- var MAX_LST_SOL_RATE = 3;
75299
- function decodeStakePool(data) {
75300
- if (data.length < LAST_UPDATE_EPOCH_OFFSET + 8) {
75301
- throw new Error(`Invalid StakePool account size: ${data.length}`);
75302
- }
75303
- if (data[0] !== ACCOUNT_TYPE_STAKE_POOL) {
75304
- throw new Error(`Invalid StakePool account type: ${data[0]}`);
75305
- }
75306
- const totalLamports = data.readBigUInt64LE(TOTAL_LAMPORTS_OFFSET);
75307
- const poolTokenSupply = data.readBigUInt64LE(POOL_TOKEN_SUPPLY_OFFSET);
75308
- const lastUpdateEpoch = Number(data.readBigUInt64LE(LAST_UPDATE_EPOCH_OFFSET));
75309
- if (poolTokenSupply === 0n) {
75310
- throw new Error("StakePool has zero token supply");
75311
- }
75312
- const exchangeRate = new BigNumber3__default.default(totalLamports.toString()).div(
75313
- new BigNumber3__default.default(poolTokenSupply.toString())
75314
- );
75315
- if (!exchangeRate.gt(0) || exchangeRate.gte(MAX_LST_SOL_RATE)) {
75316
- throw new Error(`StakePool LST/SOL rate out of bounds: ${exchangeRate.toString()}`);
75317
- }
75318
- return {
75319
- totalLamports,
75320
- poolTokenSupply,
75321
- lastUpdateEpoch,
75322
- exchangeRate
75323
- };
75324
- }
75325
75472
  var GAMMA_VAULT_PROGRAM_ID = new web3_js.PublicKey(
75326
75473
  "GaMmanX9i4jGmqDZZD2tbD6B2v9p21btenPneMXnTczV"
75327
75474
  );
@@ -85171,144 +85318,71 @@ var fetchScopeOraclePricesFromChain = async (requestKeys, connection) => {
85171
85318
  }
85172
85319
  return oraclePriceByRequestKey;
85173
85320
  };
85174
- var PT_MAX_MATURITY_HORIZON_SECONDS = 5 * 365 * 24 * 60 * 60;
85175
- var MAX_SY_EXCHANGE_RATE = new BigNumber3__default.default("18446744073709551615").div(1e12);
85176
- var MAX_STAKE_POOL_EPOCH_LAG = 1;
85177
- function multiplierAccountKey(bank) {
85178
- switch (bank.config.oracleSetup) {
85179
- case "PythMSOL" /* PythMSOL */:
85180
- case "PythLST" /* PythLST */:
85181
- case "PTPyth" /* PTPyth */:
85182
- return bank.config.oracleKeys[1];
85183
- case "KaminoMSOL" /* KaminoMSOL */:
85184
- case "JuplendMSOL" /* JuplendMSOL */:
85185
- case "KaminoLST" /* KaminoLST */:
85186
- case "JuplendLST" /* JuplendLST */:
85187
- return bank.config.oracleKeys[2];
85188
- case "PTFixed" /* PTFixed */:
85189
- return bank.config.oracleKeys[0];
85190
- default:
85191
- return void 0;
85192
- }
85193
- }
85194
- function computePtMultiplier(vault, startPrice, nowSeconds) {
85195
- const maturity = vault.startTs + vault.duration;
85196
- if (vault.duration <= 0 || maturity > nowSeconds + PT_MAX_MATURITY_HORIZON_SECONDS) {
85197
- throw new Error("Exponent vault has an invalid maturity schedule");
85198
- }
85199
- if (!vault.lastSeenSyExchangeRate.gt(0) || vault.lastSeenSyExchangeRate.gt(MAX_SY_EXCHANGE_RATE)) {
85200
- throw new Error("Exponent vault SY exchange rate out of bounds");
85201
- }
85202
- if (vault.ptSupply === 0n) {
85203
- throw new Error("Exponent vault has zero PT supply");
85204
- }
85205
- if (vault.lastSeenSyExchangeRate.lt(vault.allTimeHighSyExchangeRate)) {
85206
- throw new Error("Exponent vault is in emergency mode");
85207
- }
85208
- let expectedRate;
85209
- if (nowSeconds <= vault.startTs) {
85210
- expectedRate = startPrice;
85211
- } else if (nowSeconds >= maturity) {
85212
- expectedRate = new BigNumber3__default.default(1);
85213
- } else {
85214
- const progress = new BigNumber3__default.default(nowSeconds - vault.startTs).div(vault.duration);
85215
- expectedRate = startPrice.plus(new BigNumber3__default.default(1).minus(startPrice).times(progress));
85216
- }
85217
- const syPerPt = new BigNumber3__default.default(vault.syForPt.toString()).div(
85218
- new BigNumber3__default.default(vault.ptSupply.toString())
85219
- );
85220
- const redemptionCap = syPerPt.times(vault.lastSeenSyExchangeRate);
85221
- return BigNumber3__default.default.min(expectedRate, redemptionCap);
85222
- }
85321
+
85322
+ // src/services/price/services/oracle-multiplier.service.ts
85223
85323
  var fetchOracleMultipliers = async (banks, opts) => {
85224
- const multipliedBanks = banks.filter((bank) => multiplierAccountKey(bank) !== void 0);
85225
- if (!multipliedBanks.length) {
85324
+ const inputs = banks.map(getOracleMultiplierBankInput).filter((input) => input !== void 0);
85325
+ if (!inputs.length) {
85226
85326
  return {};
85227
85327
  }
85228
85328
  if (!opts) {
85229
85329
  console.warn(
85230
- `fetchOracleMultipliers: no oracleMultiplierOpts provided; ${multipliedBanks.length} multiplier-priced bank(s) will have zero prices`
85330
+ `fetchOracleMultipliers: no oracleMultiplierOpts provided; ${inputs.length} multiplier-priced bank(s) will have zero prices`
85231
85331
  );
85232
85332
  return {};
85233
85333
  }
85234
85334
  if (opts.mode === "api") {
85235
- return fetchOracleMultipliersFromAPI(
85236
- multipliedBanks.map((bank) => bank.address.toBase58()),
85237
- opts.multiplierData.endpoint,
85238
- { queryKey: opts.multiplierData.queryKey }
85239
- );
85335
+ return fetchOracleMultipliersFromAPI(inputs, opts.multiplierData.endpoint, {
85336
+ queryKey: opts.multiplierData.queryKey
85337
+ });
85240
85338
  }
85241
- return fetchOracleMultipliersFromChain(multipliedBanks, opts.connection);
85339
+ return fetchOracleMultipliersFromChain(inputs, opts.connection);
85242
85340
  };
85243
- var fetchOracleMultipliersFromAPI = async (bankAddresses, apiEndpoint, opts) => {
85244
- const queryKey = opts?.queryKey ?? "bankAddresses";
85245
- const response = await fetch(`${apiEndpoint}?${queryKey}=${bankAddresses.join(",")}`);
85341
+ var fetchOracleMultipliersFromAPI = async (inputs, apiEndpoint, opts) => {
85342
+ const accountStates = await fetchMultiplierAccountStatesFromAPI(
85343
+ inputs.map((input) => input.multiplierAccountKey),
85344
+ apiEndpoint,
85345
+ opts
85346
+ );
85347
+ return computeOracleMultipliers(inputs, accountStates);
85348
+ };
85349
+ var fetchOracleMultipliersFromChain = async (inputs, connection) => {
85350
+ const accountStates = await fetchMultiplierAccountStates(
85351
+ inputs.map((input) => input.multiplierAccountKey),
85352
+ connection
85353
+ );
85354
+ return computeOracleMultipliers(inputs, accountStates);
85355
+ };
85356
+ var fetchMultiplierAccountStatesFromAPI = async (accountKeys, apiEndpoint, opts) => {
85357
+ const queryKey = opts?.queryKey ?? "multiplierAccounts";
85358
+ const uniqueKeys = Array.from(new Set(accountKeys));
85359
+ const response = await fetch(`${apiEndpoint}?${queryKey}=${uniqueKeys.join(",")}`);
85246
85360
  if (!response.ok) {
85247
85361
  throw new Error("Failed to fetch price multiplier data");
85248
85362
  }
85249
85363
  const { data } = await response.json();
85250
- return Object.fromEntries(
85251
- Object.entries(data).map(([bankAddress, multiplier]) => [bankAddress, Number(multiplier)]).filter(([, multiplier]) => Number.isFinite(multiplier))
85252
- );
85364
+ return data;
85253
85365
  };
85254
- var fetchOracleMultipliersFromChain = async (multipliedBanks, connection) => {
85255
- const accountKeyByBank = new Map(
85256
- multipliedBanks.map((bank) => [bank.address.toBase58(), multiplierAccountKey(bank).toBase58()])
85257
- );
85258
- const uniqueAccountKeys = Array.from(new Set(accountKeyByBank.values()));
85259
- const accountAis = await chunkedGetRawMultipleAccountInfoOrderedWithNulls(
85260
- connection,
85261
- uniqueAccountKeys
85262
- );
85263
- const isLstSetup = (setup) => setup === "PythLST" /* PythLST */ || setup === "KaminoLST" /* KaminoLST */ || setup === "JuplendLST" /* JuplendLST */;
85264
- const currentEpoch = multipliedBanks.some((bank) => isLstSetup(bank.config.oracleSetup)) ? (await connection.getEpochInfo()).epoch : 0;
85265
- const accountDataByKey = {};
85266
- uniqueAccountKeys.forEach((accountKey, index) => {
85267
- accountDataByKey[accountKey] = accountAis[index]?.data;
85268
- });
85269
- const multiplierByBank = {};
85270
- const nowSeconds = Math.floor(Date.now() / 1e3);
85271
- for (const bank of multipliedBanks) {
85272
- const bankAddress = bank.address.toBase58();
85273
- const data = accountDataByKey[accountKeyByBank.get(bankAddress)];
85366
+ var fetchMultiplierAccountStates = async (accountKeys, connection) => {
85367
+ const uniqueKeys = Array.from(new Set(accountKeys));
85368
+ const accountAis = await chunkedGetRawMultipleAccountInfoOrderedWithNulls(connection, uniqueKeys);
85369
+ const states = {};
85370
+ uniqueKeys.forEach((accountKey, index) => {
85371
+ const data = accountAis[index]?.data;
85274
85372
  if (!data) {
85275
- console.error(`Missing multiplier account for bank ${bankAddress}`);
85276
- continue;
85373
+ console.error(`Missing multiplier account ${accountKey}`);
85374
+ return;
85277
85375
  }
85278
- try {
85279
- switch (bank.config.oracleSetup) {
85280
- case "PythMSOL" /* PythMSOL */:
85281
- case "KaminoMSOL" /* KaminoMSOL */:
85282
- case "JuplendMSOL" /* JuplendMSOL */:
85283
- multiplierByBank[bankAddress] = decodeMarinadeState(data).msolPrice.toNumber();
85284
- break;
85285
- case "PythLST" /* PythLST */:
85286
- case "KaminoLST" /* KaminoLST */:
85287
- case "JuplendLST" /* JuplendLST */: {
85288
- const stakePool = decodeStakePool(data);
85289
- if (currentEpoch - stakePool.lastUpdateEpoch > MAX_STAKE_POOL_EPOCH_LAG) {
85290
- console.error(
85291
- `Stale stake pool for bank ${bankAddress} (last updated epoch ${stakePool.lastUpdateEpoch}, current ${currentEpoch})`
85292
- );
85293
- continue;
85294
- }
85295
- multiplierByBank[bankAddress] = stakePool.exchangeRate.toNumber();
85296
- break;
85297
- }
85298
- case "PTPyth" /* PTPyth */:
85299
- case "PTFixed" /* PTFixed */:
85300
- multiplierByBank[bankAddress] = computePtMultiplier(
85301
- decodeExponentVault(data),
85302
- bank.config.fixedPrice,
85303
- nowSeconds
85304
- ).toNumber();
85305
- break;
85306
- }
85307
- } catch (e) {
85308
- console.error(`Failed to compute multiplier for bank ${bankAddress}`, e);
85376
+ const state = decodeMultiplierAccount(data);
85377
+ if (!state) {
85378
+ console.error(`Unrecognized multiplier account ${accountKey}`);
85379
+ return;
85309
85380
  }
85310
- }
85311
- return multiplierByBank;
85381
+ states[accountKey] = state;
85382
+ });
85383
+ const hasStakePool = Object.values(states).some((state) => state.kind === "stakePool");
85384
+ const currentEpoch = hasStakePool ? (await connection.getEpochInfo()).epoch : 0;
85385
+ return { states, currentEpoch };
85312
85386
  };
85313
85387
  var fetchOracleData = async (banks, opts) => {
85314
85388
  const { zeroOracleBanks, isolatedAssetBanks, collateralAssetBanks, fixedAssetBanks } = classifyBanksForOracleStrategy(banks);
@@ -89584,6 +89658,8 @@ exports.computeMaxDepositForBank = computeMaxDepositForBank;
89584
89658
  exports.computeMaxLeverage = computeMaxLeverage;
89585
89659
  exports.computeMaxWithdrawForBank = computeMaxWithdrawForBank;
89586
89660
  exports.computeNetApy = computeNetApy;
89661
+ exports.computeOracleMultiplier = computeOracleMultiplier;
89662
+ exports.computeOracleMultipliers = computeOracleMultipliers;
89587
89663
  exports.computeProjectedActiveBalancesNoCpi = computeProjectedActiveBalancesNoCpi;
89588
89664
  exports.computeProjectedActiveBanksNoCpi = computeProjectedActiveBanksNoCpi;
89589
89665
  exports.computePtMultiplier = computePtMultiplier;
@@ -89607,6 +89683,7 @@ exports.createEmptyBalance = createEmptyBalance;
89607
89683
  exports.decodeAccountRaw = decodeAccountRaw;
89608
89684
  exports.decodeBankRaw = decodeBankRaw;
89609
89685
  exports.decodeInstruction = decodeInstruction;
89686
+ exports.decodeMultiplierAccount = decodeMultiplierAccount;
89610
89687
  exports.decompileV0Transaction = decompileV0Transaction;
89611
89688
  exports.deriveBankEmissionsAuth = deriveBankEmissionsAuth;
89612
89689
  exports.deriveBankEmissionsVault = deriveBankEmissionsVault;
@@ -89650,6 +89727,8 @@ exports.fetchMarginfiAccountAddresses = fetchMarginfiAccountAddresses;
89650
89727
  exports.fetchMarginfiAccountAddressesHoldingBank = fetchMarginfiAccountAddressesHoldingBank;
89651
89728
  exports.fetchMarginfiAccountData = fetchMarginfiAccountData;
89652
89729
  exports.fetchMultipleBanks = fetchMultipleBanks;
89730
+ exports.fetchMultiplierAccountStates = fetchMultiplierAccountStates;
89731
+ exports.fetchMultiplierAccountStatesFromAPI = fetchMultiplierAccountStatesFromAPI;
89653
89732
  exports.fetchNativeStakeAccounts = fetchNativeStakeAccounts;
89654
89733
  exports.fetchOracleData = fetchOracleData;
89655
89734
  exports.fetchOracleMultipliers = fetchOracleMultipliers;
@@ -89710,6 +89789,7 @@ exports.getKaminoStatesDto = getKaminoStatesDto;
89710
89789
  exports.getLiabilityQuantity = getLiabilityQuantity;
89711
89790
  exports.getLiabilityShares = getLiabilityShares;
89712
89791
  exports.getLiabilityWeight = getLiabilityWeight;
89792
+ exports.getOracleMultiplierBankInput = getOracleMultiplierBankInput;
89713
89793
  exports.getOracleSourceFromBank = getOracleSourceFromBank;
89714
89794
  exports.getOracleSourceFromOracleSetup = getOracleSourceFromOracleSetup;
89715
89795
  exports.getOracleSourceNameFromKey = getOracleSourceNameFromKey;