@perena/vault-sdk 1.0.48 → 1.0.50

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.js CHANGED
@@ -149,7 +149,7 @@ var require_compat = __commonJS({
149
149
  exports2.fromWeb3PublicKey = fromWeb3PublicKey;
150
150
  exports2.toWeb3PublicKey = toWeb3PublicKey;
151
151
  exports2.asWeb3PublicKey = asWeb3PublicKey2;
152
- exports2.toKitInstruction = toKitInstruction35;
152
+ exports2.toKitInstruction = toKitInstruction36;
153
153
  exports2.fromKitInstruction = fromKitInstruction3;
154
154
  var kit_1 = require("@solana/kit");
155
155
  var web3_js_1 = require("@solana/web3.js");
@@ -165,7 +165,7 @@ var require_compat = __commonJS({
165
165
  exports2.toAddress = fromWeb3PublicKey;
166
166
  exports2.fromWeb3Pk = fromWeb3PublicKey;
167
167
  exports2.toWeb3Pk = toWeb3PublicKey;
168
- function toKitInstruction35(ix) {
168
+ function toKitInstruction36(ix) {
169
169
  return {
170
170
  programAddress: ix.programId.toBase58(),
171
171
  data: new Uint8Array(ix.data),
@@ -253,9 +253,9 @@ var require_meta = __commonJS({
253
253
  exports2.toCustomAccountMeta = toCustomAccountMeta;
254
254
  exports2.toCustomAccountMetaFromWeb3AccountMeta = toCustomAccountMetaFromWeb3AccountMeta;
255
255
  var roles_1 = require_roles();
256
- function toCustomAccountMeta(address14, isWritable, requiredAtaDetails, isSigner) {
256
+ function toCustomAccountMeta(address15, isWritable, requiredAtaDetails, isSigner) {
257
257
  const role = (0, roles_1.getAccountRole)(isWritable ?? false, isSigner ?? false);
258
- return { address: address14, role, isRequiredAta: requiredAtaDetails };
258
+ return { address: address15, role, isRequiredAta: requiredAtaDetails };
259
259
  }
260
260
  function toCustomAccountMetaFromWeb3AccountMeta(web3AccountMeta) {
261
261
  return toCustomAccountMeta(web3AccountMeta.pubkey.toBase58(), web3AccountMeta.isWritable, void 0, web3AccountMeta.isSigner);
@@ -1236,8 +1236,8 @@ var require_cpiClient = __commonJS({
1236
1236
  var kit_1 = require("@solana/kit");
1237
1237
  var common_1 = require_dist();
1238
1238
  var constants_1 = require_constants3();
1239
- function account(address14, role) {
1240
- return { address: address14, role };
1239
+ function account(address15, role) {
1240
+ return { address: address15, role };
1241
1241
  }
1242
1242
  function requiredAddress(value, label) {
1243
1243
  if (!value) {
@@ -1326,7 +1326,7 @@ var require_cpiClient = __commonJS({
1326
1326
  });
1327
1327
  const bankAndOracleRemainingAccounts = [
1328
1328
  account(this.accounts.bank, kit_1.AccountRole.READONLY),
1329
- ...this.accounts.oracleAccounts.map((address14) => account(address14, kit_1.AccountRole.READONLY))
1329
+ ...this.accounts.oracleAccounts.map((address15) => account(address15, kit_1.AccountRole.READONLY))
1330
1330
  ];
1331
1331
  return {
1332
1332
  cpiType: params.cpiType ?? common_1.CpiTypes.MARGINFI_WITHDRAW,
@@ -1479,6 +1479,140 @@ var require_dist2 = __commonJS({
1479
1479
  }
1480
1480
  });
1481
1481
 
1482
+ // ../nest/dist/priceApi.js
1483
+ var require_priceApi = __commonJS({
1484
+ "../nest/dist/priceApi.js"(exports2) {
1485
+ "use strict";
1486
+ Object.defineProperty(exports2, "__esModule", { value: true });
1487
+ exports2.NEST_API_BASE_URL = void 0;
1488
+ exports2.fetchNestVaultSharePrice = fetchNestVaultSharePrice2;
1489
+ exports2.NEST_API_BASE_URL = "https://api.nest.credit/v1";
1490
+ async function fetchNestVaultSharePrice2(vaultSlug, opts = {}) {
1491
+ const baseUrl = (opts.baseUrl ?? exports2.NEST_API_BASE_URL).replace(/\/$/, "");
1492
+ const response = await (opts.fetchFn ?? fetch)(`${baseUrl}/vaults/${encodeURIComponent(vaultSlug)}/price`);
1493
+ if (!response.ok) {
1494
+ throw new Error(`Nest price API request failed: ${response.status} ${response.statusText}`);
1495
+ }
1496
+ const body = await response.json();
1497
+ const price = [body.data?.interpolatedPrice, body.data?.price].map(Number).find((candidate) => Number.isFinite(candidate) && candidate > 0);
1498
+ if (price === void 0) {
1499
+ throw new Error("Nest price API returned no positive share price");
1500
+ }
1501
+ return price;
1502
+ }
1503
+ }
1504
+ });
1505
+
1506
+ // ../nest/dist/redemptionApi.js
1507
+ var require_redemptionApi = __commonJS({
1508
+ "../nest/dist/redemptionApi.js"(exports2) {
1509
+ "use strict";
1510
+ Object.defineProperty(exports2, "__esModule", { value: true });
1511
+ exports2.NestApiError = void 0;
1512
+ exports2.assertNestShareAmount = assertNestShareAmount;
1513
+ exports2.fetchNestRedemptionTransaction = fetchNestRedemptionTransaction2;
1514
+ exports2.fetchNestRedemptionQuote = fetchNestRedemptionQuote2;
1515
+ exports2.fetchNestRedemptionStatus = fetchNestRedemptionStatus2;
1516
+ var priceApi_1 = require_priceApi();
1517
+ var NestApiError2 = class extends Error {
1518
+ constructor(status, message2) {
1519
+ super(`Nest API (${status}): ${message2}`);
1520
+ this.status = status;
1521
+ this.name = "NestApiError";
1522
+ }
1523
+ };
1524
+ exports2.NestApiError = NestApiError2;
1525
+ function assertNestShareAmount(amount) {
1526
+ if (typeof amount !== "bigint" || amount <= 0n || amount > 0xffffffffffffffffn) {
1527
+ throw new Error("Nest share amount must be a positive u64 bigint in base units");
1528
+ }
1529
+ }
1530
+ async function request(path2, options, body) {
1531
+ const response = await (options.fetchFn ?? fetch)(`${(options.baseUrl ?? priceApi_1.NEST_API_BASE_URL).replace(/\/$/, "")}${path2}`, {
1532
+ method: body ? "POST" : "GET",
1533
+ headers: body ? { "Content-Type": "application/json" } : void 0,
1534
+ body: body ? JSON.stringify(body) : void 0,
1535
+ signal: options.signal
1536
+ });
1537
+ const payload = await response.json().catch(() => null);
1538
+ if (!response.ok) {
1539
+ throw new NestApiError2(response.status, typeof payload?.error === "string" ? payload.error : response.statusText);
1540
+ }
1541
+ if (!payload || typeof payload !== "object" || !payload.data) {
1542
+ throw new Error("Nest API returned an invalid response");
1543
+ }
1544
+ return payload.data;
1545
+ }
1546
+ async function fetchNestRedemptionTransaction2(args, options = {}) {
1547
+ assertNestShareAmount(args.rawAmountNestToken);
1548
+ const data = await request("/solana/nest/async-redeem/request/build-tx", options, {
1549
+ ...args,
1550
+ rawAmountNestToken: args.rawAmountNestToken.toString(),
1551
+ // Squads must sign both the token authority and LayerZero fee payer at execution.
1552
+ feePayer: args.owner
1553
+ });
1554
+ if (typeof data.txBase64 !== "string" || !data.txBase64.length) {
1555
+ throw new Error("Nest API returned no transaction");
1556
+ }
1557
+ return data.txBase64;
1558
+ }
1559
+ async function fetchNestRedemptionQuote2(args, options = {}) {
1560
+ assertNestShareAmount(args.rawAmountNestToken);
1561
+ const data = await request("/solana/nest/async-redeem/quote", options, {
1562
+ ...args,
1563
+ rawAmountNestToken: args.rawAmountNestToken.toString()
1564
+ });
1565
+ if (data.nestVaultSlug !== args.nestVaultSlug || data.redemptionAsset !== "USDC" || data.shareAmount !== args.rawAmountNestToken.toString() || !Number.isInteger(data.shareDecimals) || data.shareDecimals < 0 || data.shareDecimals > 18 || data.redemptionDecimals !== 6 || typeof data.redemptionAmount !== "string" || typeof data.feeAmount !== "string" || !/^\d+$/.test(data.redemptionAmount) || !/^\d+$/.test(data.feeAmount)) {
1566
+ throw new Error("Nest API returned an invalid redemption quote");
1567
+ }
1568
+ return data;
1569
+ }
1570
+ async function fetchNestRedemptionStatus2(signature, options = {}) {
1571
+ if (!/^[1-9A-HJ-NP-Za-km-z]{64,88}$/.test(signature)) {
1572
+ throw new Error("Enter a Solana withdrawal execution signature");
1573
+ }
1574
+ let data;
1575
+ try {
1576
+ data = await request(`/solana/redeem-status/${encodeURIComponent(signature)}`, options);
1577
+ } catch (error) {
1578
+ if (error instanceof NestApiError2 && error.status === 404)
1579
+ return null;
1580
+ throw error;
1581
+ }
1582
+ if (data.solanaBurnSignature !== signature || typeof data.solanaWallet !== "string" || typeof data.overallStatus !== "string" || !["solanaBurn", "plumeProcessing", "cctpAttestation", "solanaClaim"].every((key) => typeof data.steps?.[key]?.status === "string")) {
1583
+ throw new Error("Nest API returned an invalid redemption status");
1584
+ }
1585
+ return data;
1586
+ }
1587
+ }
1588
+ });
1589
+
1590
+ // ../nest/dist/index.js
1591
+ var require_dist3 = __commonJS({
1592
+ "../nest/dist/index.js"(exports2) {
1593
+ "use strict";
1594
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
1595
+ if (k2 === void 0) k2 = k;
1596
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1597
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1598
+ desc = { enumerable: true, get: function() {
1599
+ return m[k];
1600
+ } };
1601
+ }
1602
+ Object.defineProperty(o, k2, desc);
1603
+ }) : (function(o, m, k, k2) {
1604
+ if (k2 === void 0) k2 = k;
1605
+ o[k2] = m[k];
1606
+ }));
1607
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
1608
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
1609
+ };
1610
+ Object.defineProperty(exports2, "__esModule", { value: true });
1611
+ __exportStar(require_priceApi(), exports2);
1612
+ __exportStar(require_redemptionApi(), exports2);
1613
+ }
1614
+ });
1615
+
1482
1616
  // ../../node_modules/.pnpm/@jup-ag+api@6.0.48/node_modules/@jup-ag/api/dist/index.mjs
1483
1617
  var dist_exports = {};
1484
1618
  __export(dist_exports, {
@@ -2844,12 +2978,12 @@ var require_routePreInstructions = __commonJS({
2844
2978
  if (existingAta.value) {
2845
2979
  continue;
2846
2980
  }
2847
- instructions2.push(toKitInstruction35((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(new web3_js_1.PublicKey(payer), new web3_js_1.PublicKey(ata), new web3_js_1.PublicKey(user), new web3_js_1.PublicKey(mint), new web3_js_1.PublicKey(tokenProgram), spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID)));
2981
+ instructions2.push(toKitInstruction36((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(new web3_js_1.PublicKey(payer), new web3_js_1.PublicKey(ata), new web3_js_1.PublicKey(user), new web3_js_1.PublicKey(mint), new web3_js_1.PublicKey(tokenProgram), spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID)));
2848
2982
  postSuccessCacheInvalidations.push({ address: ata });
2849
2983
  }
2850
2984
  return { instructions: instructions2, postSuccessCacheInvalidations };
2851
2985
  }
2852
- function toKitInstruction35(ix) {
2986
+ function toKitInstruction36(ix) {
2853
2987
  return {
2854
2988
  programAddress: ix.programId.toBase58(),
2855
2989
  accounts: ix.keys.map((account) => ({
@@ -2978,7 +3112,7 @@ var require_client = __commonJS({
2978
3112
  });
2979
3113
 
2980
3114
  // ../../node_modules/.pnpm/jupiter@file+typescript+jupiter_bufferutil@4.1.0_fastestsmallesttextencoderdecoder@1.0._929400004aea12c8b3c9bcc7c5a22ec9/node_modules/jupiter/dist/priceApi.js
2981
- var require_priceApi = __commonJS({
3115
+ var require_priceApi2 = __commonJS({
2982
3116
  "../../node_modules/.pnpm/jupiter@file+typescript+jupiter_bufferutil@4.1.0_fastestsmallesttextencoderdecoder@1.0._929400004aea12c8b3c9bcc7c5a22ec9/node_modules/jupiter/dist/priceApi.js"(exports2) {
2983
3117
  "use strict";
2984
3118
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -3109,7 +3243,7 @@ var require_types4 = __commonJS({
3109
3243
  });
3110
3244
 
3111
3245
  // ../../node_modules/.pnpm/jupiter@file+typescript+jupiter_bufferutil@4.1.0_fastestsmallesttextencoderdecoder@1.0._929400004aea12c8b3c9bcc7c5a22ec9/node_modules/jupiter/dist/index.js
3112
- var require_dist3 = __commonJS({
3246
+ var require_dist4 = __commonJS({
3113
3247
  "../../node_modules/.pnpm/jupiter@file+typescript+jupiter_bufferutil@4.1.0_fastestsmallesttextencoderdecoder@1.0._929400004aea12c8b3c9bcc7c5a22ec9/node_modules/jupiter/dist/index.js"(exports2) {
3114
3248
  "use strict";
3115
3249
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
@@ -3132,144 +3266,10 @@ var require_dist3 = __commonJS({
3132
3266
  __exportStar(require_api(), exports2);
3133
3267
  __exportStar(require_client(), exports2);
3134
3268
  __exportStar(require_constants4(), exports2);
3135
- __exportStar(require_priceApi(), exports2);
3136
- __exportStar(require_routePreInstructions(), exports2);
3137
- __exportStar(require_sizeExactInForMinOutput(), exports2);
3138
- __exportStar(require_types4(), exports2);
3139
- }
3140
- });
3141
-
3142
- // ../nest/dist/priceApi.js
3143
- var require_priceApi2 = __commonJS({
3144
- "../nest/dist/priceApi.js"(exports2) {
3145
- "use strict";
3146
- Object.defineProperty(exports2, "__esModule", { value: true });
3147
- exports2.NEST_API_BASE_URL = void 0;
3148
- exports2.fetchNestVaultSharePrice = fetchNestVaultSharePrice2;
3149
- exports2.NEST_API_BASE_URL = "https://api.nest.credit/v1";
3150
- async function fetchNestVaultSharePrice2(vaultSlug, opts = {}) {
3151
- const baseUrl = (opts.baseUrl ?? exports2.NEST_API_BASE_URL).replace(/\/$/, "");
3152
- const response = await (opts.fetchFn ?? fetch)(`${baseUrl}/vaults/${encodeURIComponent(vaultSlug)}/price`);
3153
- if (!response.ok) {
3154
- throw new Error(`Nest price API request failed: ${response.status} ${response.statusText}`);
3155
- }
3156
- const body = await response.json();
3157
- const price = [body.data?.interpolatedPrice, body.data?.price].map(Number).find((candidate) => Number.isFinite(candidate) && candidate > 0);
3158
- if (price === void 0) {
3159
- throw new Error("Nest price API returned no positive share price");
3160
- }
3161
- return price;
3162
- }
3163
- }
3164
- });
3165
-
3166
- // ../nest/dist/redemptionApi.js
3167
- var require_redemptionApi = __commonJS({
3168
- "../nest/dist/redemptionApi.js"(exports2) {
3169
- "use strict";
3170
- Object.defineProperty(exports2, "__esModule", { value: true });
3171
- exports2.NestApiError = void 0;
3172
- exports2.assertNestShareAmount = assertNestShareAmount;
3173
- exports2.fetchNestRedemptionTransaction = fetchNestRedemptionTransaction2;
3174
- exports2.fetchNestRedemptionQuote = fetchNestRedemptionQuote2;
3175
- exports2.fetchNestRedemptionStatus = fetchNestRedemptionStatus2;
3176
- var priceApi_1 = require_priceApi2();
3177
- var NestApiError2 = class extends Error {
3178
- constructor(status, message2) {
3179
- super(`Nest API (${status}): ${message2}`);
3180
- this.status = status;
3181
- this.name = "NestApiError";
3182
- }
3183
- };
3184
- exports2.NestApiError = NestApiError2;
3185
- function assertNestShareAmount(amount) {
3186
- if (typeof amount !== "bigint" || amount <= 0n || amount > 0xffffffffffffffffn) {
3187
- throw new Error("Nest share amount must be a positive u64 bigint in base units");
3188
- }
3189
- }
3190
- async function request(path2, options, body) {
3191
- const response = await (options.fetchFn ?? fetch)(`${(options.baseUrl ?? priceApi_1.NEST_API_BASE_URL).replace(/\/$/, "")}${path2}`, {
3192
- method: body ? "POST" : "GET",
3193
- headers: body ? { "Content-Type": "application/json" } : void 0,
3194
- body: body ? JSON.stringify(body) : void 0,
3195
- signal: options.signal
3196
- });
3197
- const payload = await response.json().catch(() => null);
3198
- if (!response.ok) {
3199
- throw new NestApiError2(response.status, typeof payload?.error === "string" ? payload.error : response.statusText);
3200
- }
3201
- if (!payload || typeof payload !== "object" || !payload.data) {
3202
- throw new Error("Nest API returned an invalid response");
3203
- }
3204
- return payload.data;
3205
- }
3206
- async function fetchNestRedemptionTransaction2(args, options = {}) {
3207
- assertNestShareAmount(args.rawAmountNestToken);
3208
- const data = await request("/solana/nest/async-redeem/request/build-tx", options, {
3209
- ...args,
3210
- rawAmountNestToken: args.rawAmountNestToken.toString(),
3211
- // Squads must sign both the token authority and LayerZero fee payer at execution.
3212
- feePayer: args.owner
3213
- });
3214
- if (typeof data.txBase64 !== "string" || !data.txBase64.length) {
3215
- throw new Error("Nest API returned no transaction");
3216
- }
3217
- return data.txBase64;
3218
- }
3219
- async function fetchNestRedemptionQuote2(args, options = {}) {
3220
- assertNestShareAmount(args.rawAmountNestToken);
3221
- const data = await request("/solana/nest/async-redeem/quote", options, {
3222
- ...args,
3223
- rawAmountNestToken: args.rawAmountNestToken.toString()
3224
- });
3225
- if (data.nestVaultSlug !== args.nestVaultSlug || data.redemptionAsset !== "USDC" || data.shareAmount !== args.rawAmountNestToken.toString() || !Number.isInteger(data.shareDecimals) || data.shareDecimals < 0 || data.shareDecimals > 18 || data.redemptionDecimals !== 6 || typeof data.redemptionAmount !== "string" || typeof data.feeAmount !== "string" || !/^\d+$/.test(data.redemptionAmount) || !/^\d+$/.test(data.feeAmount)) {
3226
- throw new Error("Nest API returned an invalid redemption quote");
3227
- }
3228
- return data;
3229
- }
3230
- async function fetchNestRedemptionStatus2(signature, options = {}) {
3231
- if (!/^[1-9A-HJ-NP-Za-km-z]{64,88}$/.test(signature)) {
3232
- throw new Error("Enter a Solana withdrawal execution signature");
3233
- }
3234
- let data;
3235
- try {
3236
- data = await request(`/solana/redeem-status/${encodeURIComponent(signature)}`, options);
3237
- } catch (error) {
3238
- if (error instanceof NestApiError2 && error.status === 404)
3239
- return null;
3240
- throw error;
3241
- }
3242
- if (data.solanaBurnSignature !== signature || typeof data.solanaWallet !== "string" || typeof data.overallStatus !== "string" || !["solanaBurn", "plumeProcessing", "cctpAttestation", "solanaClaim"].every((key) => typeof data.steps?.[key]?.status === "string")) {
3243
- throw new Error("Nest API returned an invalid redemption status");
3244
- }
3245
- return data;
3246
- }
3247
- }
3248
- });
3249
-
3250
- // ../nest/dist/index.js
3251
- var require_dist4 = __commonJS({
3252
- "../nest/dist/index.js"(exports2) {
3253
- "use strict";
3254
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
3255
- if (k2 === void 0) k2 = k;
3256
- var desc = Object.getOwnPropertyDescriptor(m, k);
3257
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
3258
- desc = { enumerable: true, get: function() {
3259
- return m[k];
3260
- } };
3261
- }
3262
- Object.defineProperty(o, k2, desc);
3263
- }) : (function(o, m, k, k2) {
3264
- if (k2 === void 0) k2 = k;
3265
- o[k2] = m[k];
3266
- }));
3267
- var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
3268
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
3269
- };
3270
- Object.defineProperty(exports2, "__esModule", { value: true });
3271
3269
  __exportStar(require_priceApi2(), exports2);
3272
- __exportStar(require_redemptionApi(), exports2);
3270
+ __exportStar(require_routePreInstructions(), exports2);
3271
+ __exportStar(require_sizeExactInForMinOutput(), exports2);
3272
+ __exportStar(require_types4(), exports2);
3273
3273
  }
3274
3274
  });
3275
3275
 
@@ -3302,7 +3302,7 @@ __export(index_exports, {
3302
3302
  DEFAULT_JUNIOR_WITHDRAWAL_LOCKUP_SECS: () => DEFAULT_JUNIOR_WITHDRAWAL_LOCKUP_SECS,
3303
3303
  DEFAULT_MAX_ACCEPTABLE_APY_BPS: () => DEFAULT_MAX_ACCEPTABLE_APY_BPS,
3304
3304
  DEFAULT_MAX_ACCOUNTS: () => DEFAULT_MAX_ACCOUNTS,
3305
- DEFAULT_MINTS: () => import_common60.DEFAULT_MINTS,
3305
+ DEFAULT_MINTS: () => import_common62.DEFAULT_MINTS,
3306
3306
  DEFAULT_MIN_AMOUNT_UI: () => DEFAULT_MIN_AMOUNT_UI,
3307
3307
  DEFAULT_ORACLE_STALENESS_THRESHOLD_SECS: () => DEFAULT_ORACLE_STALENESS_THRESHOLD_SECS,
3308
3308
  DEFAULT_PRICE_ORACLE_ACCOUNT: () => DEFAULT_PRICE_ORACLE_ACCOUNT,
@@ -3311,6 +3311,7 @@ __export(index_exports, {
3311
3311
  DEFAULT_REBALANCE_BAND_BPS: () => DEFAULT_REBALANCE_BAND_BPS,
3312
3312
  DEFAULT_SLIPPAGE_BPS: () => DEFAULT_SLIPPAGE_BPS,
3313
3313
  DEFAULT_TARGET_LOCAL_BPS: () => DEFAULT_TARGET_LOCAL_BPS,
3314
+ DEFAULT_TARGET_LOCAL_USDC_TVL_BPS: () => DEFAULT_TARGET_LOCAL_USDC_TVL_BPS,
3314
3315
  DEFAULT_VAULT_ID: () => DEFAULT_VAULT_ID,
3315
3316
  DisableCircuitBreakerBuilder: () => DisableCircuitBreakerBuilder,
3316
3317
  DistributeIncentiveBuilder: () => DistributeIncentiveBuilder,
@@ -3338,6 +3339,8 @@ __export(index_exports, {
3338
3339
  LOCAL_PROTOCOL_ADMIN: () => LOCAL_PROTOCOL_ADMIN,
3339
3340
  LargeBalanceChangeError: () => LargeBalanceChangeError,
3340
3341
  LivePriceSource: () => LivePriceSource,
3342
+ MANAGER_WALLET_NAV_DROP_TRIGGER_BPS: () => MANAGER_WALLET_NAV_DROP_TRIGGER_BPS,
3343
+ MANAGER_WALLET_NAV_TOLERANCE_BPS: () => MANAGER_WALLET_NAV_TOLERANCE_BPS,
3341
3344
  MAX_APY_ANCHOR_WINDOW_SECS: () => MAX_APY_ANCHOR_WINDOW_SECS,
3342
3345
  MAX_BALANCE_CHANGE_BPS: () => MAX_BALANCE_CHANGE_BPS,
3343
3346
  MAX_CONSENSUS_SIGNERS: () => MAX_CONSENSUS_SIGNERS,
@@ -3349,7 +3352,7 @@ __export(index_exports, {
3349
3352
  ManagerRedepositAssetBuilder: () => ManagerRedepositAssetBuilder,
3350
3353
  ManagerWithdrawAssetBuilder: () => ManagerWithdrawAssetBuilder,
3351
3354
  MarginfiPositionProvider: () => MarginfiPositionProvider,
3352
- MintRegistry: () => import_common60.MintRegistry,
3355
+ MintRegistry: () => import_common62.MintRegistry,
3353
3356
  MockYieldTracker: () => MockYieldTracker,
3354
3357
  NEST_API_BASE_URL: () => import_nest2.NEST_API_BASE_URL,
3355
3358
  NEST_RWA_SHARE_MINT: () => NEST_RWA_SHARE_MINT,
@@ -3370,6 +3373,7 @@ __export(index_exports, {
3370
3373
  RemoveAssetHoldingBuilder: () => RemoveAssetHoldingBuilder,
3371
3374
  ReportIncentiveV3Builder: () => ReportIncentiveV3Builder,
3372
3375
  RequestJuniorTrancheWithdrawBuilder: () => RequestJuniorTrancheWithdrawBuilder,
3376
+ RpcManagerWalletBalanceSource: () => RpcManagerWalletBalanceSource,
3373
3377
  SHARE_DECIMALS: () => SHARE_DECIMALS,
3374
3378
  SYSTEM_PROGRAM: () => SYSTEM_PROGRAM,
3375
3379
  SetAssetPriceOracleBuilder: () => SetAssetPriceOracleBuilder,
@@ -3409,6 +3413,7 @@ __export(index_exports, {
3409
3413
  VaultClient: () => VaultClient,
3410
3414
  VaultQuoteClient: () => VaultQuoteClient,
3411
3415
  VaultReallocationBuilder: () => VaultReallocationBuilder,
3416
+ WITHDRAWABLE_RESERVE_FLOOR_BPS: () => WITHDRAWABLE_RESERVE_FLOOR_BPS,
3412
3417
  WithdrawalQueueService: () => WithdrawalQueueService,
3413
3418
  accountingUnitPriceToUsd: () => accountingUnitPriceToUsd,
3414
3419
  addCashflowUpdate: () => addCashflowUpdate,
@@ -3418,8 +3423,10 @@ __export(index_exports, {
3418
3423
  assertNoUnconfirmedYieldPayments: () => assertNoUnconfirmedYieldPayments,
3419
3424
  buildHoldingUpdate: () => buildHoldingUpdate,
3420
3425
  buildMarginfiWithdrawInteraction: () => buildMarginfiWithdrawInteraction,
3426
+ buildNestDepositRequest: () => buildNestDepositRequest,
3421
3427
  buildNestWithdrawalRequest: () => buildNestWithdrawalRequest,
3422
3428
  buildUpdates: () => buildUpdates,
3429
+ candidateGrossNav: () => candidateGrossNav,
3423
3430
  coerceBool: () => coerceBool3,
3424
3431
  collectSamples: () => collectSamples,
3425
3432
  confirmYieldPayment: () => confirmYieldPayment,
@@ -3431,6 +3438,7 @@ __export(index_exports, {
3431
3438
  createVaultClient: () => createVaultClient,
3432
3439
  createYieldPayment: () => createYieldPayment,
3433
3440
  dateToStr: () => dateToStr,
3441
+ decodeNestDepositRequest: () => decodeNestDepositRequest,
3434
3442
  decodeNestWithdrawalRequest: () => decodeNestWithdrawalRequest,
3435
3443
  decodePendingConsensusSigners: () => decodePendingConsensusSigners,
3436
3444
  defaultKeypairPath: () => defaultKeypairPath,
@@ -3478,16 +3486,19 @@ __export(index_exports, {
3478
3486
  loadKeypair: () => loadKeypair,
3479
3487
  logProspectiveApy: () => logProspectiveApy,
3480
3488
  makeProvider: () => makeProvider,
3489
+ managerReconciliationStateKey: () => managerReconciliationStateKey,
3481
3490
  mintTokensTo: () => mintTokensTo,
3482
- mints: () => import_common60.mints,
3491
+ mints: () => import_common62.mints,
3483
3492
  mostFrequent: () => mostFrequent,
3484
3493
  parseExternalLiquidityRefs: () => parseExternalLiquidityRefs,
3485
3494
  planRebalance: () => planRebalance,
3486
3495
  prepareSquadsProposalUpload: () => prepareSquadsProposalUpload,
3487
3496
  prepareVaultTransaction: () => prepareVaultTransaction,
3497
+ previousPhysicalNav: () => previousPhysicalNav,
3488
3498
  priceInAccountingUnit: () => priceInAccountingUnit,
3489
3499
  readI64LE: () => readI64LE,
3490
3500
  readSplMintSupply: () => readSplMintSupply,
3501
+ reconcileManagerWalletBalances: () => reconcileManagerWalletBalances,
3491
3502
  refreshLiveOraclePrices: () => refreshLiveOraclePrices,
3492
3503
  resolveExternalWithdraw: () => resolveExternalWithdraw,
3493
3504
  resolveKeypairPath: () => resolveKeypairPath,
@@ -17833,9 +17844,13 @@ async function simulateSquadsProposalExecution(args) {
17833
17844
  return value;
17834
17845
  }
17835
17846
  async function prepareVaultTransaction(args) {
17836
- const { connection, proposer, instructions: instructions2 } = args;
17847
+ const { connection, proposer } = args;
17848
+ let instructions2 = [...args.instructions];
17849
+ const ephemeralKeys = args.ephemeralSignerKeys ?? [];
17837
17850
  const route = findSquadsWalletRoute(proposer, args.squadsRoutes ?? []);
17838
17851
  if (!route) {
17852
+ if (ephemeralKeys.length)
17853
+ throw new Error("Ephemeral signers require a Squads route");
17839
17854
  return {
17840
17855
  kind: "direct",
17841
17856
  transaction: new import_web324.Transaction().add(...instructions2),
@@ -17863,6 +17878,44 @@ async function prepareVaultTransaction(args) {
17863
17878
  );
17864
17879
  }
17865
17880
  const transactionIndex = BigInt(multisig.transactionIndex.toString()) + 1n;
17881
+ if (ephemeralKeys.length > 255 || new Set(ephemeralKeys.map(String)).size !== ephemeralKeys.length) {
17882
+ throw new Error("Invalid Squads ephemeral signer keys");
17883
+ }
17884
+ const [transactionPda] = squads.getTransactionPda({
17885
+ multisigPda: route.multisigPda,
17886
+ index: transactionIndex
17887
+ });
17888
+ const replacements = /* @__PURE__ */ new Map();
17889
+ ephemeralKeys.forEach((key, index) => {
17890
+ if (key.equals(proposer) || key.equals(route.vaultPda) || !instructions2.some(
17891
+ (ix) => ix.keys.some((meta) => meta.isSigner && meta.pubkey.equals(key))
17892
+ ) || instructions2.some(
17893
+ (ix) => ix.programId.equals(key) || ix.data.includes(key.toBuffer())
17894
+ )) {
17895
+ throw new Error(
17896
+ "Ephemeral signer must be a separate account-meta signer, never embedded in instruction data"
17897
+ );
17898
+ }
17899
+ replacements.set(
17900
+ key.toBase58(),
17901
+ squads.getEphemeralSignerPda({
17902
+ transactionPda,
17903
+ ephemeralSignerIndex: index
17904
+ })[0]
17905
+ );
17906
+ });
17907
+ if (replacements.size) {
17908
+ instructions2 = instructions2.map(
17909
+ (ix) => new import_web324.TransactionInstruction({
17910
+ programId: ix.programId,
17911
+ data: ix.data,
17912
+ keys: ix.keys.map((meta) => ({
17913
+ ...meta,
17914
+ pubkey: replacements.get(meta.pubkey.toBase58()) ?? meta.pubkey
17915
+ }))
17916
+ })
17917
+ );
17918
+ }
17866
17919
  const { blockhash } = await connection.getLatestBlockhash("confirmed");
17867
17920
  if (!args.skipSimulation) {
17868
17921
  await simulateSquadsProposalExecution({
@@ -17883,7 +17936,7 @@ async function prepareVaultTransaction(args) {
17883
17936
  transactionIndex,
17884
17937
  creator: proposer,
17885
17938
  vaultIndex: route.vaultIndex,
17886
- ephemeralSigners: 0,
17939
+ ephemeralSigners: ephemeralKeys.length,
17887
17940
  transactionMessage,
17888
17941
  addressLookupTableAccounts: args.addressLookupTableAccounts,
17889
17942
  memo: route.memo
@@ -20498,15 +20551,199 @@ async function refreshLiveOraclePrices({
20498
20551
  return results.some((result) => Boolean(result.signature));
20499
20552
  }
20500
20553
 
20501
- // src/services/consensusOracle/pipeline/pricingInputs.ts
20554
+ // src/services/consensusOracle/pipeline/managerWalletReconciliation.ts
20502
20555
  var import_common51 = __toESM(require_dist());
20556
+
20557
+ // src/services/consensusOracle/sources/nestPriceSource.ts
20558
+ var import_kit13 = require("@solana/kit");
20559
+ var import_nest = __toESM(require_dist3());
20560
+ var import_nest2 = __toESM(require_dist3());
20561
+ var NEST_VAULT_SLUG = "nest-perena-vault";
20562
+ var NEST_RWA_SHARE_MINT = (0, import_kit13.address)(
20563
+ "VyXKJnVhkSkB6KAozSZCiLQbuB1k1r6Nu4etNYVo5LJ"
20564
+ );
20565
+ async function fetchNestTokenPrice(nestVaultSlug = NEST_VAULT_SLUG, opts = {}) {
20566
+ return (0, import_nest.fetchNestVaultSharePrice)(nestVaultSlug, opts);
20567
+ }
20568
+ var NestPriceSource = class {
20569
+ constructor(opts = {}) {
20570
+ this.shareMint = opts.shareMint ?? NEST_RWA_SHARE_MINT;
20571
+ this.nestVaultSlug = opts.nestVaultSlug ?? NEST_VAULT_SLUG;
20572
+ this.options = { baseUrl: opts.baseUrl, fetchFn: opts.fetchFn };
20573
+ }
20574
+ async fetchUsdPrices(mints2) {
20575
+ if (!mints2.some((mint) => mint.toString() === this.shareMint.toString())) {
20576
+ return {};
20577
+ }
20578
+ return {
20579
+ [this.shareMint.toString()]: await (0, import_nest.fetchNestVaultSharePrice)(
20580
+ this.nestVaultSlug,
20581
+ this.options
20582
+ )
20583
+ };
20584
+ }
20585
+ };
20586
+
20587
+ // src/services/consensusOracle/pipeline/managerWalletReconciliation.ts
20588
+ var MANAGER_WALLET_NAV_DROP_TRIGGER_BPS = 10n;
20589
+ var MANAGER_WALLET_NAV_TOLERANCE_BPS = 5n;
20590
+ var BPS = 10000n;
20591
+ var U64_MAX = 0xffffffffffffffffn;
20592
+ function previousPhysicalNav(state) {
20593
+ const banked = toBigInt2(state.config.apy?.accruedApyBalance);
20594
+ return toBigInt2(state.accounting?.tvl) + (banked > 0n ? banked : 0n);
20595
+ }
20596
+ function candidateGrossNav(state, updates) {
20597
+ const byIndex = /* @__PURE__ */ new Map();
20598
+ for (const update of updates) {
20599
+ const holding = state.holdings[update.holdingIndex];
20600
+ if (!holding || (0, import_common51.fromWeb3Pk)(holding.mint) !== update.mint || holding.decimals !== update.decimals || byIndex.has(update.holdingIndex)) {
20601
+ throw new Error(`Invalid NAV update for holding #${update.holdingIndex}`);
20602
+ }
20603
+ byIndex.set(update.holdingIndex, update);
20604
+ }
20605
+ return state.holdings.reduce((nav, holding, index) => {
20606
+ if ((0, import_common51.fromWeb3Pk)(holding.mint) === SYSTEM_PROGRAM) return nav;
20607
+ const update = byIndex.get(index);
20608
+ const local = toBigInt2(holding.localAmount);
20609
+ const external = update?.externalAmount ?? toBigInt2(holding.externalAmount);
20610
+ if (local < 0n || external < 0n || local + external > U64_MAX) {
20611
+ throw new Error(`Invalid NAV amount for holding #${index}`);
20612
+ }
20613
+ if (local + external === 0n) return nav;
20614
+ const price = update && variantName2(holding.priceOracleType).toLowerCase() === CONSENSUS_ORACLE_VARIANT ? update.price : toBigInt2(holding.price);
20615
+ if (price <= 0n || !Number.isInteger(holding.decimals) || holding.decimals < 0 || holding.decimals > 18) {
20616
+ throw new Error(
20617
+ `Cannot value holding #${index} for manager reconciliation`
20618
+ );
20619
+ }
20620
+ const nextNav = nav + (local + external) * price / 10n ** BigInt(holding.decimals);
20621
+ if (nextNav > U64_MAX) throw new Error("Candidate NAV exceeds u64");
20622
+ return nextNav;
20623
+ }, 0n);
20624
+ }
20625
+ function retainPendingNestShares(state, updates) {
20626
+ return updates.map((update) => {
20627
+ if (update.mint !== NEST_RWA_SHARE_MINT) return update;
20628
+ const recorded = toBigInt2(
20629
+ state.holdings[update.holdingIndex]?.externalAmount
20630
+ );
20631
+ if (recorded <= update.externalAmount) return update;
20632
+ return {
20633
+ ...update,
20634
+ pendingNestAmount: recorded - update.externalAmount,
20635
+ externalAmount: recorded
20636
+ };
20637
+ });
20638
+ }
20639
+ async function reconcileManagerWalletBalances({
20640
+ vault,
20641
+ vaultState,
20642
+ updates,
20643
+ source,
20644
+ log = () => {
20645
+ }
20646
+ }) {
20647
+ const previousNav = previousPhysicalNav(vaultState);
20648
+ if (updates.some(
20649
+ (update) => (update.managerWalletAmount ?? 0n) !== 0n || (update.pendingNestAmount ?? 0n) !== 0n
20650
+ )) {
20651
+ throw new Error("Manager reconciliation requires fresh source amounts");
20652
+ }
20653
+ const pendingUpdates = retainPendingNestShares(vaultState, updates);
20654
+ if (!source || previousNav <= 0n) {
20655
+ return {
20656
+ accepted: false,
20657
+ updates: pendingUpdates,
20658
+ previousNav,
20659
+ candidateNav: 0n
20660
+ };
20661
+ }
20662
+ const candidateNav = candidateGrossNav(vaultState, updates);
20663
+ const result = {
20664
+ accepted: false,
20665
+ updates: pendingUpdates,
20666
+ previousNav,
20667
+ candidateNav
20668
+ };
20669
+ if ((previousNav - candidateNav) * BPS < previousNav * MANAGER_WALLET_NAV_DROP_TRIGGER_BPS) {
20670
+ return result;
20671
+ }
20672
+ const baseUpdates = updates.filter(
20673
+ (update) => coerceBool3(vaultState.holdings[update.holdingIndex].isBase)
20674
+ );
20675
+ const mints2 = baseUpdates.map((update) => update.mint);
20676
+ if (mints2.length === 0) return result;
20677
+ if (new Set(mints2).size !== mints2.length) {
20678
+ throw new Error("Duplicate base mint in manager reconciliation");
20679
+ }
20680
+ if (vaultState.holdings.some(
20681
+ (holding) => coerceBool3(holding.isBase) && !mints2.includes((0, import_common51.fromWeb3Pk)(holding.mint))
20682
+ )) {
20683
+ throw new Error(
20684
+ "Cannot reconcile all vault base assets with oracle reports"
20685
+ );
20686
+ }
20687
+ const manager = (0, import_common51.fromWeb3Pk)(vaultState.roles.manager);
20688
+ if (manager === SYSTEM_PROGRAM || manager === vault) {
20689
+ throw new Error("Invalid manager wallet for NAV reconciliation");
20690
+ }
20691
+ log(
20692
+ `vault ${vault}: NAV ${candidateNav} is at least 0.1% below ${previousNav}; checking manager ${manager}`
20693
+ );
20694
+ const amounts = await source.fetchBalances(manager, mints2);
20695
+ const adjusted = updates.map((update) => {
20696
+ if (!mints2.includes(update.mint)) return update;
20697
+ const amount = amounts.get(update.mint) ?? 0n;
20698
+ if (typeof amount !== "bigint" || amount < 0n || amount > U64_MAX) {
20699
+ throw new Error(`Invalid manager base-asset balance for ${update.mint}`);
20700
+ }
20701
+ return {
20702
+ ...update,
20703
+ managerWalletAmount: amount,
20704
+ externalAmount: update.externalAmount + amount
20705
+ };
20706
+ });
20707
+ const adjustedNav = candidateGrossNav(vaultState, adjusted);
20708
+ const delta = adjustedNav - previousNav;
20709
+ const absoluteDelta = delta < 0n ? -delta : delta;
20710
+ const accepted = adjustedNav > candidateNav && absoluteDelta * BPS <= previousNav * MANAGER_WALLET_NAV_TOLERANCE_BPS;
20711
+ log(
20712
+ `vault ${vault}: manager wallet ${accepted ? "accepted" : "rejected"}; adjusted NAV ${adjustedNav}, previous NAV ${previousNav}, allowed difference \xB10.05%`
20713
+ );
20714
+ return {
20715
+ accepted,
20716
+ updates: accepted ? adjusted : pendingUpdates,
20717
+ previousNav,
20718
+ candidateNav,
20719
+ adjustedNav
20720
+ };
20721
+ }
20722
+ function managerReconciliationStateKey(state) {
20723
+ return JSON.stringify({
20724
+ manager: (0, import_common51.fromWeb3Pk)(state.roles.manager),
20725
+ previousNav: previousPhysicalNav(state).toString(),
20726
+ holdings: state.holdings.map((holding) => [
20727
+ (0, import_common51.fromWeb3Pk)(holding.mint),
20728
+ holding.decimals,
20729
+ variantName2(holding.priceOracleType),
20730
+ coerceBool3(holding.isBase),
20731
+ toBigInt2(holding.localAmount).toString(),
20732
+ toBigInt2(holding.externalAmount).toString(),
20733
+ toBigInt2(holding.price).toString()
20734
+ ])
20735
+ });
20736
+ }
20737
+
20738
+ // src/services/consensusOracle/pipeline/pricingInputs.ts
20739
+ var import_common52 = __toESM(require_dist());
20503
20740
  async function gatherPricingInputs(deps, target, vaultState, reportableHoldings, log = () => {
20504
20741
  }) {
20505
20742
  const consensusMints = reportableHoldings.filter(
20506
20743
  ({ holding }) => variantName2(holding.priceOracleType).toLowerCase() === CONSENSUS_ORACLE_VARIANT
20507
- ).map(({ holding }) => (0, import_common51.fromWeb3Pk)(holding.mint));
20744
+ ).map(({ holding }) => (0, import_common52.fromWeb3Pk)(holding.mint));
20508
20745
  const baseHolding = vaultState.holdings.find((h) => coerceBool3(h.isBase));
20509
- const baseMint = baseHolding ? (0, import_common51.fromWeb3Pk)(baseHolding.mint) : consensusMints[0];
20746
+ const baseMint = baseHolding ? (0, import_common52.fromWeb3Pk)(baseHolding.mint) : consensusMints[0];
20510
20747
  if (!baseMint) {
20511
20748
  throw new Error(`vault has no holdings \u2014 cannot determine base asset`);
20512
20749
  }
@@ -20590,11 +20827,11 @@ function reconcilePositionSnapshots(snapshots, vault, log) {
20590
20827
  }
20591
20828
 
20592
20829
  // src/services/consensusOracle/pipeline/receiptMints.ts
20593
- var import_common52 = __toESM(require_dist());
20830
+ var import_common53 = __toESM(require_dist());
20594
20831
  async function fetchReceiptMints(client, vault, vaultState) {
20595
20832
  const receiptMints = /* @__PURE__ */ new Set();
20596
20833
  if (vaultState.mint) {
20597
- receiptMints.add((0, import_common52.fromWeb3Pk)(vaultState.mint).toString());
20834
+ receiptMints.add((0, import_common53.fromWeb3Pk)(vaultState.mint).toString());
20598
20835
  }
20599
20836
  if (!coerceBool3(vaultState.tranchingEnabled)) return receiptMints;
20600
20837
  const trancheState = await client.account.fetchVaultTrancheStateForVault(
@@ -20602,19 +20839,19 @@ async function fetchReceiptMints(client, vault, vaultState) {
20602
20839
  { fresh: true }
20603
20840
  );
20604
20841
  receiptMints.add(
20605
- (0, import_common52.fromWeb3Pk)(trancheState.config.juniorMint).toString()
20842
+ (0, import_common53.fromWeb3Pk)(trancheState.config.juniorMint).toString()
20606
20843
  );
20607
20844
  receiptMints.add(
20608
- (0, import_common52.fromWeb3Pk)(trancheState.config.seniorMint).toString()
20845
+ (0, import_common53.fromWeb3Pk)(trancheState.config.seniorMint).toString()
20609
20846
  );
20610
20847
  return receiptMints;
20611
20848
  }
20612
20849
 
20613
20850
  // src/services/consensusOracle/pipeline/settlement.ts
20614
- var import_common54 = __toESM(require_dist());
20851
+ var import_common55 = __toESM(require_dist());
20615
20852
 
20616
20853
  // src/services/consensusOracle/pipeline/yieldAccounts.ts
20617
- var import_common53 = __toESM(require_dist());
20854
+ var import_common54 = __toESM(require_dist());
20618
20855
  async function assertNoUnconfirmedYieldPayments(yieldTracker, target) {
20619
20856
  const accountNames = [
20620
20857
  ...new Set(
@@ -20656,7 +20893,7 @@ async function withDiscoveredYieldAccounts(yieldTracker, target, vaultState, exc
20656
20893
  );
20657
20894
  if (namesToAttach.length === 0) return target;
20658
20895
  const baseHolding = vaultState.holdings.find((holding) => {
20659
- const mint = (0, import_common53.fromWeb3Pk)(holding.mint).toString();
20896
+ const mint = (0, import_common54.fromWeb3Pk)(holding.mint).toString();
20660
20897
  return coerceBool3(holding.isBase) && !excludedMints.has(mint);
20661
20898
  });
20662
20899
  if (!baseHolding) {
@@ -20664,7 +20901,7 @@ async function withDiscoveredYieldAccounts(yieldTracker, target, vaultState, exc
20664
20901
  `vault ${target.vault}: tagged yield accounts found but no base holding is available`
20665
20902
  );
20666
20903
  }
20667
- const baseMint = (0, import_common53.fromWeb3Pk)(baseHolding.mint);
20904
+ const baseMint = (0, import_common54.fromWeb3Pk)(baseHolding.mint);
20668
20905
  const holdings = [...target.holdings ?? []];
20669
20906
  const existingIndex = holdings.findIndex(
20670
20907
  (holding) => holding.mint.toString() === baseMint.toString()
@@ -20697,13 +20934,14 @@ async function settleVault2({
20697
20934
  updates,
20698
20935
  vaultState,
20699
20936
  nowSecs,
20700
- log
20937
+ log,
20938
+ beforeSubmit
20701
20939
  }) {
20702
20940
  const vault = target.vault;
20703
20941
  log(`vault ${vault}: submitting ${updates.length} consensus asset update(s)`);
20704
20942
  for (const update of updates) {
20705
20943
  log(
20706
- ` holding #${update.holdingIndex} ${update.mint}: price=${update.price} external_amount=${update.externalAmount} [lp=${update.lpAmount} tracked=${update.trackedValueAmount} principal=${update.trackedPrincipalAmount} yield=${update.yieldAmount}]`
20944
+ ` holding #${update.holdingIndex} ${update.mint}: price=${update.price} external_amount=${update.externalAmount} [pendingNest=${update.pendingNestAmount ?? 0n} managerWallet=${update.managerWalletAmount ?? 0n} lp=${update.lpAmount} tracked=${update.trackedValueAmount} principal=${update.trackedPrincipalAmount} yield=${update.yieldAmount}]`
20707
20945
  );
20708
20946
  }
20709
20947
  try {
@@ -20725,6 +20963,7 @@ async function settleVault2({
20725
20963
  );
20726
20964
  }
20727
20965
  await assertNoUnconfirmedYieldPayments(yieldTracker, target);
20966
+ await beforeSubmit?.();
20728
20967
  const updateSignature = await oracle.updateAssetConsensusPrice(
20729
20968
  signer,
20730
20969
  {
@@ -20765,7 +21004,7 @@ async function logProspectiveApy({
20765
21004
  );
20766
21005
  const prospectiveNav = vaultState.holdings.reduce(
20767
21006
  (sum, holding, holdingIndex) => {
20768
- const mint = (0, import_common54.fromWeb3Pk)(holding.mint).toString();
21007
+ const mint = (0, import_common55.fromWeb3Pk)(holding.mint).toString();
20769
21008
  if (mint === SYSTEM_PROGRAM) return sum;
20770
21009
  const update = updatesByIndex.get(holdingIndex);
20771
21010
  const localAmount = toBigInt2(holding.localAmount);
@@ -20821,7 +21060,7 @@ async function discoverVaultsForSigner(client, signer, opts = {}) {
20821
21060
  }
20822
21061
 
20823
21062
  // src/services/consensusOracle/sources/jupiterPriceSource.ts
20824
- var import_jupiter = __toESM(require_dist3());
21063
+ var import_jupiter = __toESM(require_dist4());
20825
21064
  var JupiterPriceSource = class {
20826
21065
  constructor(opts = {}) {
20827
21066
  this.opts = opts;
@@ -20831,36 +21070,6 @@ var JupiterPriceSource = class {
20831
21070
  }
20832
21071
  };
20833
21072
 
20834
- // src/services/consensusOracle/sources/nestPriceSource.ts
20835
- var import_kit13 = require("@solana/kit");
20836
- var import_nest = __toESM(require_dist4());
20837
- var import_nest2 = __toESM(require_dist4());
20838
- var NEST_VAULT_SLUG = "nest-perena-vault";
20839
- var NEST_RWA_SHARE_MINT = (0, import_kit13.address)(
20840
- "VyXKJnVhkSkB6KAozSZCiLQbuB1k1r6Nu4etNYVo5LJ"
20841
- );
20842
- async function fetchNestTokenPrice(nestVaultSlug = NEST_VAULT_SLUG, opts = {}) {
20843
- return (0, import_nest.fetchNestVaultSharePrice)(nestVaultSlug, opts);
20844
- }
20845
- var NestPriceSource = class {
20846
- constructor(opts = {}) {
20847
- this.shareMint = opts.shareMint ?? NEST_RWA_SHARE_MINT;
20848
- this.nestVaultSlug = opts.nestVaultSlug ?? NEST_VAULT_SLUG;
20849
- this.options = { baseUrl: opts.baseUrl, fetchFn: opts.fetchFn };
20850
- }
20851
- async fetchUsdPrices(mints2) {
20852
- if (!mints2.some((mint) => mint.toString() === this.shareMint.toString())) {
20853
- return {};
20854
- }
20855
- return {
20856
- [this.shareMint.toString()]: await (0, import_nest.fetchNestVaultSharePrice)(
20857
- this.nestVaultSlug,
20858
- this.options
20859
- )
20860
- };
20861
- }
20862
- };
20863
-
20864
21073
  // src/services/consensusOracle/sources/livePriceSource.ts
20865
21074
  var LivePriceSource = class {
20866
21075
  constructor(opts = {}) {
@@ -20882,6 +21091,59 @@ var LivePriceSource = class {
20882
21091
  }
20883
21092
  };
20884
21093
 
21094
+ // src/services/consensusOracle/sources/managerWalletBalanceSource.ts
21095
+ var import_web330 = require("@solana/web3.js");
21096
+ var import_spl_token20 = require("@solana/spl-token");
21097
+ var RpcManagerWalletBalanceSource = class {
21098
+ constructor(connection) {
21099
+ this.connection = connection;
21100
+ }
21101
+ async fetchBalances(manager, mints2) {
21102
+ const wanted = new Set(mints2);
21103
+ if (wanted.size === 0) return /* @__PURE__ */ new Map();
21104
+ const owner = new import_web330.PublicKey(manager);
21105
+ const programs = [import_spl_token20.TOKEN_PROGRAM_ID, import_spl_token20.TOKEN_2022_PROGRAM_ID];
21106
+ const responses = await Promise.all(
21107
+ programs.map(
21108
+ (programId) => this.connection.getParsedTokenAccountsByOwner(
21109
+ owner,
21110
+ { programId },
21111
+ "confirmed"
21112
+ )
21113
+ )
21114
+ );
21115
+ const amounts = /* @__PURE__ */ new Map();
21116
+ const seen = /* @__PURE__ */ new Set();
21117
+ for (let index = 0; index < responses.length; index += 1) {
21118
+ for (const { pubkey: pubkey2, account } of responses[index].value) {
21119
+ const data = account.data;
21120
+ if (!("parsed" in data) || data.parsed?.type !== "account") {
21121
+ throw new Error(`Unparsed manager token account ${pubkey2}`);
21122
+ }
21123
+ const info = data.parsed.info;
21124
+ if (!account.owner.equals(programs[index]) || info?.owner !== manager) {
21125
+ throw new Error(`Invalid manager token account owner ${pubkey2}`);
21126
+ }
21127
+ if (!wanted.has(info.mint)) continue;
21128
+ const key = pubkey2.toBase58();
21129
+ if (seen.has(key))
21130
+ throw new Error(`Duplicate manager token account ${key}`);
21131
+ seen.add(key);
21132
+ const raw = info.tokenAmount?.amount;
21133
+ if (typeof raw !== "string" || !/^\d+$/.test(raw)) {
21134
+ throw new Error(`Invalid manager token balance ${key}`);
21135
+ }
21136
+ const amount = BigInt(raw);
21137
+ if (amount > 0xffffffffffffffffn) {
21138
+ throw new Error(`Manager token balance exceeds u64: ${key}`);
21139
+ }
21140
+ amounts.set(info.mint, (amounts.get(info.mint) ?? 0n) + amount);
21141
+ }
21142
+ }
21143
+ return amounts;
21144
+ }
21145
+ };
21146
+
20885
21147
  // src/services/consensusOracle/positions/externalPositions.ts
20886
21148
  var ExternalPositionRegistry = class {
20887
21149
  constructor(providers = [], log = () => {
@@ -20918,7 +21180,7 @@ var StaticPositionProvider = class {
20918
21180
 
20919
21181
  // src/services/consensusOracle/positions/kaminoPositionProvider.ts
20920
21182
  var import_kit14 = require("@solana/kit");
20921
- var import_web330 = require("@solana/web3.js");
21183
+ var import_web331 = require("@solana/web3.js");
20922
21184
  var import_klend_sdk = require("@kamino-finance/klend-sdk");
20923
21185
  async function readKaminoBalance(manager, vault, sharesHolder) {
20924
21186
  const userShares = await manager.getUserSharesBalanceSingleVault(
@@ -20955,7 +21217,7 @@ var KaminoPositionProvider = class {
20955
21217
  const amount = await readKaminoBalance(
20956
21218
  manager,
20957
21219
  kVault,
20958
- new import_web330.PublicKey(sharesHolder)
21220
+ new import_web331.PublicKey(sharesHolder)
20959
21221
  );
20960
21222
  out.push({ mint: ref.mint, amount });
20961
21223
  }
@@ -20964,7 +21226,7 @@ var KaminoPositionProvider = class {
20964
21226
  };
20965
21227
 
20966
21228
  // src/services/consensusOracle/positions/marginfiPositionProvider.ts
20967
- var import_web331 = require("@solana/web3.js");
21229
+ var import_web332 = require("@solana/web3.js");
20968
21230
  var import_marginfi2 = __toESM(require_dist2());
20969
21231
  var MarginfiPositionProvider = class {
20970
21232
  constructor(connection, log = () => {
@@ -20975,8 +21237,8 @@ var MarginfiPositionProvider = class {
20975
21237
  async positionsFor(ctx) {
20976
21238
  const refs = ctx.refs.filter((r) => r.kind === "marginfi");
20977
21239
  if (refs.length === 0) return [];
20978
- const explicitBanks = refs.map((r) => r.marginfiBank).filter(Boolean).map((bank) => new import_web331.PublicKey(bank));
20979
- const autoAccountPks = refs.filter((r) => !r.marginfiBank).map((r) => r.marginfiAccount).filter(Boolean).map((account) => new import_web331.PublicKey(account));
21240
+ const explicitBanks = refs.map((r) => r.marginfiBank).filter(Boolean).map((bank) => new import_web332.PublicKey(bank));
21241
+ const autoAccountPks = refs.filter((r) => !r.marginfiBank).map((r) => r.marginfiAccount).filter(Boolean).map((account) => new import_web332.PublicKey(account));
20980
21242
  const autoBanks = [];
20981
21243
  for (const accountPk of autoAccountPks) {
20982
21244
  try {
@@ -21005,14 +21267,14 @@ var MarginfiPositionProvider = class {
21005
21267
  if (bank) {
21006
21268
  const amount = await (0, import_marginfi2.readMarginfiBankBalance)(
21007
21269
  client,
21008
- new import_web331.PublicKey(account),
21009
- new import_web331.PublicKey(bank)
21270
+ new import_web332.PublicKey(account),
21271
+ new import_web332.PublicKey(bank)
21010
21272
  );
21011
21273
  out.push({ mint: ref.mint, amount });
21012
21274
  } else {
21013
21275
  const balances = await (0, import_marginfi2.readAllMarginfiBalances)(
21014
21276
  client,
21015
- new import_web331.PublicKey(account)
21277
+ new import_web332.PublicKey(account)
21016
21278
  );
21017
21279
  for (const { mint, amount } of balances) {
21018
21280
  out.push({ mint: mint.toBase58(), amount });
@@ -21219,6 +21481,7 @@ function createLiveConsensusOracleDeps(connection, opts = {}) {
21219
21481
  });
21220
21482
  const deps = {
21221
21483
  priceSource: new LivePriceSource(),
21484
+ managerWalletBalances: new RpcManagerWalletBalanceSource(connection),
21222
21485
  yieldTracker: {
21223
21486
  async getAccountNamesForVault(vault) {
21224
21487
  const accounts2 = await getAccounts();
@@ -21252,7 +21515,7 @@ function createLiveConsensusOracleDeps(connection, opts = {}) {
21252
21515
  }
21253
21516
 
21254
21517
  // src/services/consensusOracle/consensusOracleService.ts
21255
- var import_common55 = __toESM(require_dist());
21518
+ var import_common56 = __toESM(require_dist());
21256
21519
  var ConsensusOracleService = class {
21257
21520
  constructor(client, deps) {
21258
21521
  this.client = client;
@@ -21288,7 +21551,7 @@ var ConsensusOracleService = class {
21288
21551
  receiptMints
21289
21552
  );
21290
21553
  const filteredCount = vaultState.holdings.filter(
21291
- (holding) => receiptMints.has((0, import_common55.fromWeb3Pk)(holding.mint).toString())
21554
+ (holding) => receiptMints.has((0, import_common56.fromWeb3Pk)(holding.mint).toString())
21292
21555
  ).length;
21293
21556
  if (filteredCount > 0) {
21294
21557
  log(
@@ -21318,18 +21581,35 @@ var ConsensusOracleService = class {
21318
21581
  reportableHoldings,
21319
21582
  log
21320
21583
  );
21321
- const updates = await buildUpdates(
21584
+ const sourcedUpdates = await buildUpdates(
21322
21585
  this.deps.yieldTracker,
21323
21586
  reportableHoldings,
21324
21587
  inputs
21325
21588
  );
21326
- assertNoLargeBalanceChanges(
21327
- target.vault,
21589
+ const reconciliation = await reconcileManagerWalletBalances({
21590
+ vault: target.vault,
21328
21591
  vaultState,
21329
- updates,
21330
- this.nowSecs(),
21592
+ updates: sourcedUpdates,
21593
+ source: this.deps.managerWalletBalances,
21331
21594
  log
21332
- );
21595
+ });
21596
+ const updates = reconciliation.updates;
21597
+ const needsRevalidation = reconciliation.accepted || // A new withdrawal can be queued after the first vault read, too.
21598
+ updates.some((update) => update.mint === NEST_RWA_SHARE_MINT);
21599
+ const reconciliationStateKey = needsRevalidation ? managerReconciliationStateKey(vaultState) : void 0;
21600
+ if (!reconciliation.accepted) {
21601
+ assertNoLargeBalanceChanges(
21602
+ target.vault,
21603
+ vaultState,
21604
+ updates,
21605
+ this.nowSecs(),
21606
+ log
21607
+ );
21608
+ } else {
21609
+ log(
21610
+ `vault ${target.vault}: manager NAV reconciliation passed; allowing cross-asset external balance changes`
21611
+ );
21612
+ }
21333
21613
  if (dryRun) {
21334
21614
  log(`vault ${target.vault}: dry run, ${updates.length} holding(s)`);
21335
21615
  try {
@@ -21369,7 +21649,29 @@ var ConsensusOracleService = class {
21369
21649
  updates,
21370
21650
  vaultState,
21371
21651
  nowSecs: this.nowSecs(),
21372
- log
21652
+ log,
21653
+ beforeSubmit: needsRevalidation ? async () => {
21654
+ const freshState = await this.fetchDecodedVault(target.vault);
21655
+ if (managerReconciliationStateKey(freshState) !== reconciliationStateKey) {
21656
+ throw new Error(
21657
+ "Vault changed during manager-wallet reconciliation; retry with fresh inputs"
21658
+ );
21659
+ }
21660
+ if (!reconciliation.accepted) return;
21661
+ const fresh = await reconcileManagerWalletBalances({
21662
+ vault: target.vault,
21663
+ vaultState: freshState,
21664
+ updates: sourcedUpdates,
21665
+ source: this.deps.managerWalletBalances
21666
+ });
21667
+ if (!fresh.accepted || fresh.updates.some(
21668
+ (update, index) => update.externalAmount !== updates[index].externalAmount
21669
+ )) {
21670
+ throw new Error(
21671
+ "Manager wallet changed during reconciliation; retry with fresh inputs"
21672
+ );
21673
+ }
21674
+ } : void 0
21373
21675
  });
21374
21676
  return {
21375
21677
  vault: target.vault,
@@ -21469,11 +21771,12 @@ async function runLiveConsensusOracle(env, oracleSigner, opts = {}) {
21469
21771
 
21470
21772
  // src/services/externalLiquidityIntegrityService.ts
21471
21773
  var import_kit15 = require("@solana/kit");
21472
- var import_web332 = require("@solana/web3.js");
21473
- var import_common56 = __toESM(require_dist());
21774
+ var import_web333 = require("@solana/web3.js");
21775
+ var import_common57 = __toESM(require_dist());
21474
21776
  var import_marginfi3 = __toESM(require_dist2());
21475
21777
  var DEFAULT_MIN_AMOUNT_UI = 1;
21476
21778
  var DEFAULT_TARGET_LOCAL_BPS = 50;
21779
+ var DEFAULT_TARGET_LOCAL_USDC_TVL_BPS = 150;
21477
21780
  var DEFAULT_REBALANCE_BAND_BPS = 2e3;
21478
21781
  var BPS_DENOMINATOR4 = 10000n;
21479
21782
  function toRawAmount(uiAmount, decimals) {
@@ -21492,7 +21795,7 @@ function parseActiveSlots(externalLiquidity) {
21492
21795
  if (discriminant === 0) continue;
21493
21796
  if (discriminant !== 1) continue;
21494
21797
  const pubkeyBytes = new Uint8Array(data.slice(8, 40));
21495
- const userAccount = (0, import_common56.toAddress)(new import_web332.PublicKey(pubkeyBytes));
21798
+ const userAccount = (0, import_common57.toAddress)(new import_web333.PublicKey(pubkeyBytes));
21496
21799
  results.push({ index: i, source: "marginfi", userAccount });
21497
21800
  }
21498
21801
  return results;
@@ -21517,11 +21820,12 @@ function planRebalance(params) {
21517
21820
  localAmount,
21518
21821
  externalAmount,
21519
21822
  targetLocalBps,
21823
+ targetLocalAmount,
21520
21824
  rebalanceBandBps,
21521
21825
  minRaw
21522
21826
  } = params;
21523
21827
  const total = localAmount + externalAmount;
21524
- const targetLocal = total * BigInt(Math.round(targetLocalBps)) / BPS_DENOMINATOR4;
21828
+ const targetLocal = targetLocalAmount ?? total * BigInt(Math.round(targetLocalBps)) / BPS_DENOMINATOR4;
21525
21829
  const band = targetLocal * BigInt(Math.round(rebalanceBandBps)) / BPS_DENOMINATOR4;
21526
21830
  const threshold = band > minRaw ? band : minRaw;
21527
21831
  if (localAmount > targetLocal) {
@@ -21549,6 +21853,7 @@ var ExternalLiquidityIntegrityService = class {
21549
21853
  const dryRun = opts.dryRun ?? false;
21550
21854
  const minAmountUi = opts.minAmountUi ?? DEFAULT_MIN_AMOUNT_UI;
21551
21855
  const targetLocalBps = opts.targetLocalBps ?? DEFAULT_TARGET_LOCAL_BPS;
21856
+ const targetLocalUsdcTvlBps = opts.targetLocalUsdcTvlBps ?? DEFAULT_TARGET_LOCAL_USDC_TVL_BPS;
21552
21857
  const rebalanceBandBps = opts.rebalanceBandBps ?? DEFAULT_REBALANCE_BAND_BPS;
21553
21858
  if (dryRun) {
21554
21859
  log(
@@ -21556,7 +21861,12 @@ var ExternalLiquidityIntegrityService = class {
21556
21861
  );
21557
21862
  }
21558
21863
  log(`Minimum rebalance: ${minAmountUi} token(s) (~$${minAmountUi})`);
21559
- log(`Target local share: ${targetLocalBps / 100}% of each holding`);
21864
+ log(
21865
+ `Target local USDC: ${targetLocalUsdcTvlBps / 100}% of total vault TVL`
21866
+ );
21867
+ log(
21868
+ `Target local share: ${targetLocalBps / 100}% of each non-USDC holding`
21869
+ );
21560
21870
  log(
21561
21871
  `Rebalance band: ${rebalanceBandBps / 100}% of target (${targetLocalBps * (1 - rebalanceBandBps / 1e4) / 100}%\u2013${targetLocalBps * (1 + rebalanceBandBps / 1e4) / 100}% of holding)`
21562
21872
  );
@@ -21576,7 +21886,13 @@ var ExternalLiquidityIntegrityService = class {
21576
21886
  vaultState,
21577
21887
  hwManager,
21578
21888
  log,
21579
- { dryRun, minAmountUi, targetLocalBps, rebalanceBandBps }
21889
+ {
21890
+ dryRun,
21891
+ minAmountUi,
21892
+ targetLocalBps,
21893
+ targetLocalUsdcTvlBps,
21894
+ rebalanceBandBps
21895
+ }
21580
21896
  );
21581
21897
  summary.vaultsProcessed++;
21582
21898
  summary.totalDeposited += result.deposited;
@@ -21594,6 +21910,7 @@ var ExternalLiquidityIntegrityService = class {
21594
21910
  const dryRun = opts.dryRun ?? false;
21595
21911
  const minAmountUi = opts.minAmountUi ?? DEFAULT_MIN_AMOUNT_UI;
21596
21912
  const targetLocalBps = opts.targetLocalBps ?? DEFAULT_TARGET_LOCAL_BPS;
21913
+ const targetLocalUsdcTvlBps = opts.targetLocalUsdcTvlBps ?? DEFAULT_TARGET_LOCAL_USDC_TVL_BPS;
21597
21914
  const rebalanceBandBps = opts.rebalanceBandBps ?? DEFAULT_REBALANCE_BAND_BPS;
21598
21915
  const result = {
21599
21916
  vault,
@@ -21608,8 +21925,8 @@ var ExternalLiquidityIntegrityService = class {
21608
21925
  result.skipped++;
21609
21926
  return result;
21610
21927
  }
21611
- const hwManagerAddress = (0, import_common56.fromWeb3Pk)(hwManager.publicKey);
21612
- const vaultPk = new import_web332.PublicKey(vault.toString());
21928
+ const hwManagerAddress = (0, import_common57.fromWeb3Pk)(hwManager.publicKey);
21929
+ const vaultPk = new import_web333.PublicKey(vault.toString());
21613
21930
  const registeredHwManager = pubkeyStr(
21614
21931
  vaultState.roles.hwManager
21615
21932
  );
@@ -21642,10 +21959,27 @@ var ExternalLiquidityIntegrityService = class {
21642
21959
  const externalAmount = toBigInt3(holding.externalAmount);
21643
21960
  const decimals = Number(holding.decimals ?? 0);
21644
21961
  const minRaw = toRawAmount(minAmountUi, decimals);
21962
+ let targetLocalAmount;
21963
+ if (mintAddress === import_common57.USDC_MINT) {
21964
+ const tvl = toBigInt3(vaultState.accounting.tvl);
21965
+ const price = toBigInt3(holding.price);
21966
+ const stalenessThreshold = Number(toBigInt3(vaultState.config.priceStalenessThresholdSecs)) || DEFAULT_PRICE_STALENESS_THRESHOLD_SECS;
21967
+ if (tvl <= 0n || price <= 0n || Math.floor(Date.now() / 1e3) - Number(toBigInt3(holding.lastUpdateTs)) > stalenessThreshold) {
21968
+ log(
21969
+ `Vault ${vault}: cannot size local USDC target without TVL and a fresh USDC price \u2014 skipping`
21970
+ );
21971
+ result.skipped++;
21972
+ continue;
21973
+ }
21974
+ const numerator = tvl * BigInt(Math.round(targetLocalUsdcTvlBps)) * 10n ** BigInt(decimals);
21975
+ const denominator = BPS_DENOMINATOR4 * price;
21976
+ targetLocalAmount = (numerator + denominator - 1n) / denominator;
21977
+ }
21645
21978
  const plan = planRebalance({
21646
21979
  localAmount,
21647
21980
  externalAmount,
21648
21981
  targetLocalBps,
21982
+ targetLocalAmount,
21649
21983
  rebalanceBandBps,
21650
21984
  minRaw
21651
21985
  });
@@ -21736,7 +22070,7 @@ var ExternalLiquidityIntegrityService = class {
21736
22070
  marginfiAccounts.tokenProgram,
21737
22071
  true
21738
22072
  );
21739
- const cpiRefs = (0, import_common56.createCpiRefs)([
22073
+ const cpiRefs = (0, import_common57.createCpiRefs)([
21740
22074
  direction === "deposit" ? marginfiClient.deposit_cpi({
21741
22075
  marginfiAccount: slot.userAccount,
21742
22076
  authority: vault,
@@ -21788,14 +22122,15 @@ var ExternalLiquidityIntegrityService = class {
21788
22122
 
21789
22123
  // src/services/idleLiquidityService.ts
21790
22124
  var import_kit16 = require("@solana/kit");
21791
- var import_spl_token20 = require("@solana/spl-token");
22125
+ var import_spl_token21 = require("@solana/spl-token");
21792
22126
  var import_marginfi_client_v2 = require("@mrgnlabs/marginfi-client-v2");
21793
- var import_web333 = require("@solana/web3.js");
21794
- var import_common57 = __toESM(require_dist());
21795
- var import_jupiter2 = __toESM(require_dist3());
22127
+ var import_web334 = require("@solana/web3.js");
22128
+ var import_common58 = __toESM(require_dist());
22129
+ var import_jupiter2 = __toESM(require_dist4());
21796
22130
  var import_marginfi4 = __toESM(require_dist2());
21797
22131
  var IDLE_RESERVE_FLOOR_BPS = 400;
21798
22132
  var IDLE_RESERVE_TARGET_BPS = 500;
22133
+ var WITHDRAWABLE_RESERVE_FLOOR_BPS = 150;
21799
22134
  var DEFAULT_SLIPPAGE_BPS = 30;
21800
22135
  var DEFAULT_CU_PRICE_MICRO_LAMPORTS = 1e4;
21801
22136
  var DEFAULT_MAX_ACCOUNTS = 20;
@@ -21890,8 +22225,8 @@ var IdleLiquidityService = class {
21890
22225
  let quote;
21891
22226
  try {
21892
22227
  quote = await jupiter.getQuote({
21893
- inputMint: import_common57.PST_MINT,
21894
- outputMint: import_common57.USDC_MINT,
22228
+ inputMint: import_common58.PST_MINT,
22229
+ outputMint: import_common58.USDC_MINT,
21895
22230
  amount: pstInput,
21896
22231
  slippageBps: opts.slippageBps ?? DEFAULT_SLIPPAGE_BPS,
21897
22232
  maxAccounts: DEFAULT_MAX_ACCOUNTS
@@ -21937,34 +22272,41 @@ var IdleLiquidityService = class {
21937
22272
  /** Read only the two locations that constitute the idle USDC reserve. */
21938
22273
  async fetchIdleUsdc(vault, vaultState) {
21939
22274
  const connection = this.client.provider.connection;
21940
- const vaultPk = new import_web333.PublicKey(vault);
21941
- const usdcMint = new import_web333.PublicKey(import_common57.USDC_MINT);
21942
- const ata = (0, import_spl_token20.getAssociatedTokenAddressSync)(usdcMint, vaultPk, true);
22275
+ const vaultPk = new import_web334.PublicKey(vault);
22276
+ const usdcMint = new import_web334.PublicKey(import_common58.USDC_MINT);
22277
+ const ata = (0, import_spl_token21.getAssociatedTokenAddressSync)(usdcMint, vaultPk, true);
21943
22278
  const tokenInfo = await connection.getAccountInfo(ata, "confirmed");
21944
22279
  let localAmount = 0n;
21945
22280
  if (tokenInfo) {
21946
- const tokenAccount = (0, import_spl_token20.unpackAccount)(ata, tokenInfo, import_spl_token20.TOKEN_PROGRAM_ID);
22281
+ const tokenAccount = (0, import_spl_token21.unpackAccount)(ata, tokenInfo, import_spl_token21.TOKEN_PROGRAM_ID);
21947
22282
  if (!tokenAccount.mint.equals(usdcMint) || !tokenAccount.owner.equals(vaultPk) || !tokenAccount.isInitialized) {
21948
22283
  throw new Error(`Invalid vault USDC token account: ${ata.toBase58()}`);
21949
22284
  }
21950
22285
  localAmount = tokenAccount.amount;
21951
22286
  }
21952
- const data = vaultState.externalLiquidity[0]?.data;
21953
- if (!data || data.length < 40) {
21954
- throw new Error("Invalid external-liquidity slot 0");
22287
+ const slotIndex = vaultState.externalLiquidity.findIndex(
22288
+ (slot) => slot.data[0] === 1
22289
+ );
22290
+ if (slotIndex === -1) {
22291
+ return {
22292
+ localAmount,
22293
+ marginfiAmount: 0n,
22294
+ withdrawableMarginfiAmount: 0n,
22295
+ slotIndex
22296
+ };
21955
22297
  }
21956
- if (data[0] === 0) return { localAmount, marginfiAmount: 0n };
21957
- if (data[0] !== 1) {
21958
- throw new Error("External-liquidity slot 0 is not Marginfi");
22298
+ const data = vaultState.externalLiquidity[slotIndex].data;
22299
+ if (data.length < 40) {
22300
+ throw new Error(`Invalid Project0 external-liquidity slot ${slotIndex}`);
21959
22301
  }
21960
- const positionPk = new import_web333.PublicKey(new Uint8Array(data.slice(8, 40)));
22302
+ const positionPk = new import_web334.PublicKey(new Uint8Array(data.slice(8, 40)));
21961
22303
  const positionInfo = await connection.getAccountInfo(
21962
22304
  positionPk,
21963
22305
  "confirmed"
21964
22306
  );
21965
- if (!positionInfo || !positionInfo.owner.equals(new import_web333.PublicKey(import_marginfi4.MARGINFI_PROGRAM_ID))) {
22307
+ if (!positionInfo || !positionInfo.owner.equals(new import_web334.PublicKey(import_marginfi4.MARGINFI_PROGRAM_ID))) {
21966
22308
  throw new Error(
21967
- `Invalid Marginfi slot-0 account: ${positionPk.toBase58()}`
22309
+ `Invalid Project0 slot-${slotIndex} account: ${positionPk.toBase58()}`
21968
22310
  );
21969
22311
  }
21970
22312
  const marginfi = await (0, import_marginfi4.createMarginfiReadClient)(
@@ -21973,9 +22315,10 @@ var IdleLiquidityService = class {
21973
22315
  );
21974
22316
  const position = await import_marginfi_client_v2.MarginfiAccountWrapper.fetch(positionPk, marginfi);
21975
22317
  if (!position.authority.equals(vaultPk)) {
21976
- throw new Error("Marginfi slot-0 authority is not the vault");
22318
+ throw new Error(`Project0 slot-${slotIndex} authority is not the vault`);
21977
22319
  }
21978
22320
  let marginfiAmount = 0n;
22321
+ let withdrawableMarginfiAmount = 0n;
21979
22322
  for (const balance of position.activeBalances) {
21980
22323
  const bank = marginfi.getBankByPk(balance.bankPk);
21981
22324
  if (!bank) {
@@ -21984,11 +22327,22 @@ var IdleLiquidityService = class {
21984
22327
  );
21985
22328
  }
21986
22329
  if (!bank.mint.equals(usdcMint)) continue;
21987
- marginfiAmount += BigInt(
22330
+ const deposited = BigInt(
21988
22331
  balance.computeQuantity(bank).assets.toFixed(0, 1)
21989
22332
  );
22333
+ const available = BigInt(
22334
+ bank.getTotalAssetQuantity().minus(bank.getTotalLiabilityQuantity()).toFixed(0, 1)
22335
+ );
22336
+ const bankLiquidity = available > 0n ? available : 0n;
22337
+ marginfiAmount += deposited;
22338
+ withdrawableMarginfiAmount += deposited < bankLiquidity ? deposited : bankLiquidity;
21990
22339
  }
21991
- return { localAmount, marginfiAmount };
22340
+ return {
22341
+ localAmount,
22342
+ marginfiAmount,
22343
+ withdrawableMarginfiAmount,
22344
+ slotIndex
22345
+ };
21992
22346
  }
21993
22347
  /**
21994
22348
  * Decide whether a top-up is warranted. Returns either a terminal `result`
@@ -22003,6 +22357,8 @@ var IdleLiquidityService = class {
22003
22357
  tvl,
22004
22358
  idleValue: 0n,
22005
22359
  idleBps: 0,
22360
+ withdrawableValue: 0n,
22361
+ withdrawableBps: 0,
22006
22362
  shortfallUsdc: 0n,
22007
22363
  pstSpent: 0n,
22008
22364
  usdcReceived: 0n
@@ -22012,8 +22368,8 @@ var IdleLiquidityService = class {
22012
22368
  log(`Vault ${vault}: ${reason} \u2014 skipping`);
22013
22369
  return { result: { ...empty, status: "no-tvl", reason } };
22014
22370
  }
22015
- const usdc = findHolding2(vaultState, import_common57.USDC_MINT);
22016
- const pst = findHolding2(vaultState, import_common57.PST_MINT);
22371
+ const usdc = findHolding2(vaultState, import_common58.USDC_MINT);
22372
+ const pst = findHolding2(vaultState, import_common58.PST_MINT);
22017
22373
  if (!usdc || !pst) {
22018
22374
  const reason = `vault has no ${usdc ? "PST" : "USDC"} holding`;
22019
22375
  log(`Vault ${vault}: ${reason} \u2014 skipping`);
@@ -22047,7 +22403,16 @@ var IdleLiquidityService = class {
22047
22403
  const idleAmount = balances.localAmount + balances.marginfiAmount;
22048
22404
  const idleValue = holdingValue2(usdc, idleAmount);
22049
22405
  const idleBps = Number(idleValue * 10000n / tvl);
22050
- const base = { ...empty, idleValue, idleBps };
22406
+ const withdrawableAmount = balances.localAmount + balances.withdrawableMarginfiAmount;
22407
+ const withdrawableValue = holdingValue2(usdc, withdrawableAmount);
22408
+ const withdrawableBps = Number(withdrawableValue * 10000n / tvl);
22409
+ const base = {
22410
+ ...empty,
22411
+ idleValue,
22412
+ idleBps,
22413
+ withdrawableValue,
22414
+ withdrawableBps
22415
+ };
22051
22416
  log(
22052
22417
  `Vault ${vault}: idle USDC ${formatUi2(
22053
22418
  idleAmount,
@@ -22055,13 +22420,21 @@ var IdleLiquidityService = class {
22055
22420
  )} (vault token account ${formatUi2(
22056
22421
  balances.localAmount,
22057
22422
  usdc.decimals
22058
- )} + Marginfi slot 0 ${formatUi2(
22423
+ )} + Project0 slot ${balances.slotIndex} ${formatUi2(
22059
22424
  balances.marginfiAmount,
22060
22425
  usdc.decimals
22061
22426
  )}) = ${idleBps}bps of TVL (floor ${IDLE_RESERVE_FLOOR_BPS}bps, target ${IDLE_RESERVE_TARGET_BPS}bps)`
22062
22427
  );
22063
- if (idleBps >= IDLE_RESERVE_FLOOR_BPS) {
22064
- const reason = `idle USDC ${idleBps}bps is at or above the ${IDLE_RESERVE_FLOOR_BPS}bps floor`;
22428
+ log(
22429
+ `Vault ${vault}: withdrawable USDC ${formatUi2(
22430
+ withdrawableAmount,
22431
+ usdc.decimals
22432
+ )} = ${withdrawableBps}bps of TVL (floor ${WITHDRAWABLE_RESERVE_FLOOR_BPS}bps)`
22433
+ );
22434
+ const idleBelowFloor = idleBps < IDLE_RESERVE_FLOOR_BPS;
22435
+ const withdrawableBelowFloor = withdrawableBps < WITHDRAWABLE_RESERVE_FLOOR_BPS;
22436
+ if (!idleBelowFloor && !withdrawableBelowFloor) {
22437
+ const reason = `idle USDC ${idleBps}bps and withdrawable USDC ${withdrawableBps}bps are at or above their floors`;
22065
22438
  return { result: { ...base, status: "above-floor", reason } };
22066
22439
  }
22067
22440
  for (const [name, holding] of [
@@ -22074,8 +22447,11 @@ var IdleLiquidityService = class {
22074
22447
  return { result: { ...base, status: "rebalance-cooldown", reason } };
22075
22448
  }
22076
22449
  }
22077
- const targetValue = tvl * BigInt(IDLE_RESERVE_TARGET_BPS) / 10000n;
22078
- let shortfallValue = targetValue - idleValue;
22450
+ const targetValue = (tvl * BigInt(IDLE_RESERVE_TARGET_BPS) + 9999n) / 10000n;
22451
+ const withdrawableTargetValue = (tvl * BigInt(WITHDRAWABLE_RESERVE_FLOOR_BPS) + 9999n) / 10000n;
22452
+ const idleShortfall = idleBelowFloor ? targetValue - idleValue : 0n;
22453
+ const withdrawableShortfall = withdrawableBelowFloor ? withdrawableTargetValue - withdrawableValue : 0n;
22454
+ let shortfallValue = idleShortfall > withdrawableShortfall ? idleShortfall : withdrawableShortfall;
22079
22455
  const allowance = this.remainingRebalanceAllowance(vaultState, tvl, now);
22080
22456
  if (allowance !== void 0 && allowance < shortfallValue) {
22081
22457
  if (allowance === 0n) {
@@ -22088,7 +22464,7 @@ var IdleLiquidityService = class {
22088
22464
  );
22089
22465
  shortfallValue = allowance;
22090
22466
  }
22091
- const shortfallUsdc = shortfallValue * 10n ** BigInt(usdc.decimals) / usdc.price;
22467
+ const shortfallUsdc = (shortfallValue * 10n ** BigInt(usdc.decimals) + usdc.price - 1n) / usdc.price;
22092
22468
  if (shortfallUsdc <= 0n) {
22093
22469
  const reason = "computed shortfall rounds to zero";
22094
22470
  return { result: { ...base, status: "above-floor", reason } };
@@ -22141,16 +22517,16 @@ var IdleLiquidityService = class {
22141
22517
  */
22142
22518
  async mintTokenProgram(mint) {
22143
22519
  const account = await this.client.provider.connection.getAccountInfo(
22144
- new import_web333.PublicKey(mint),
22520
+ new import_web334.PublicKey(mint),
22145
22521
  "confirmed"
22146
22522
  );
22147
22523
  if (!account) throw new Error(`Mint account not found: ${mint}`);
22148
- if (!account.owner.equals(import_spl_token20.TOKEN_PROGRAM_ID) && !account.owner.equals(import_spl_token20.TOKEN_2022_PROGRAM_ID)) {
22524
+ if (!account.owner.equals(import_spl_token21.TOKEN_PROGRAM_ID) && !account.owner.equals(import_spl_token21.TOKEN_2022_PROGRAM_ID)) {
22149
22525
  throw new Error(
22150
22526
  `Unsupported token program ${account.owner.toBase58()} for mint ${mint}`
22151
22527
  );
22152
22528
  }
22153
- return (0, import_common57.fromWeb3Pk)(account.owner);
22529
+ return (0, import_common58.fromWeb3Pk)(account.owner);
22154
22530
  }
22155
22531
  /**
22156
22532
  * Build, simulate, and (unless `dryRun`) submit the `jupiter_swap`.
@@ -22170,23 +22546,23 @@ var IdleLiquidityService = class {
22170
22546
  dryRun,
22171
22547
  log
22172
22548
  } = params;
22173
- const signer = (0, import_common57.fromWeb3Pk)(hwManager.publicKey);
22549
+ const signer = (0, import_common58.fromWeb3Pk)(hwManager.publicKey);
22174
22550
  const [sourceTokenProgram, destinationTokenProgram] = await Promise.all([
22175
- this.mintTokenProgram(import_common57.PST_MINT),
22176
- this.mintTokenProgram(import_common57.USDC_MINT)
22551
+ this.mintTokenProgram(import_common58.PST_MINT),
22552
+ this.mintTokenProgram(import_common58.USDC_MINT)
22177
22553
  ]);
22178
22554
  const jupiterCpi = await jupiter.getSwapCpiData(quote, vault, {
22179
22555
  payer: signer
22180
22556
  });
22181
- const { accounts: accounts2, refs, lookupTables } = (0, import_common57.createCpiRefs)([jupiterCpi]);
22557
+ const { accounts: accounts2, refs, lookupTables } = (0, import_common58.createCpiRefs)([jupiterCpi]);
22182
22558
  const vaultTrancheState = coerceBool4(
22183
22559
  vaultState.tranchingEnabled
22184
22560
  ) ? (await this.client.pda.deriveVaultTrancheStatePda(vault))[0] : void 0;
22185
22561
  const plan = await this.client.tx.jupiterSwap.getTx({
22186
22562
  hwManager: signer,
22187
22563
  vault,
22188
- sourceMint: import_common57.PST_MINT,
22189
- destinationMint: import_common57.USDC_MINT,
22564
+ sourceMint: import_common58.PST_MINT,
22565
+ destinationMint: import_common58.USDC_MINT,
22190
22566
  refs,
22191
22567
  accounts: accounts2,
22192
22568
  sourceTokenProgram,
@@ -22196,26 +22572,26 @@ var IdleLiquidityService = class {
22196
22572
  });
22197
22573
  const connection = this.client.provider.connection;
22198
22574
  const instructions2 = [
22199
- import_web333.ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNIT_LIMIT }),
22575
+ import_web334.ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNIT_LIMIT }),
22200
22576
  ...cuPriceMicroLamports > 0 ? [
22201
- import_web333.ComputeBudgetProgram.setComputeUnitPrice({
22577
+ import_web334.ComputeBudgetProgram.setComputeUnitPrice({
22202
22578
  microLamports: cuPriceMicroLamports
22203
22579
  })
22204
22580
  ] : [],
22205
- ...(jupiterCpi.preInstructions ?? []).map(import_common57.fromKitInstruction),
22206
- ...plan.instructions.map(import_common57.fromKitInstruction)
22581
+ ...(jupiterCpi.preInstructions ?? []).map(import_common58.fromKitInstruction),
22582
+ ...plan.instructions.map(import_common58.fromKitInstruction)
22207
22583
  ];
22208
22584
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
22209
- const lookupTableAccounts = await (0, import_common57.fetchLookupTables)(
22585
+ const lookupTableAccounts = await (0, import_common58.fetchLookupTables)(
22210
22586
  connection,
22211
22587
  plan.lookupTables ?? []
22212
22588
  );
22213
- const message2 = new import_web333.TransactionMessage({
22589
+ const message2 = new import_web334.TransactionMessage({
22214
22590
  payerKey: hwManager.publicKey,
22215
22591
  recentBlockhash: blockhash,
22216
22592
  instructions: instructions2
22217
22593
  }).compileToV0Message(lookupTableAccounts);
22218
- const transaction = new import_web333.VersionedTransaction(message2);
22594
+ const transaction = new import_web334.VersionedTransaction(message2);
22219
22595
  transaction.sign([hwManager]);
22220
22596
  if (!this.client.skipSimulation) {
22221
22597
  const simulation = await connection.simulateTransaction(transaction, {
@@ -22261,9 +22637,9 @@ var IdleLiquidityService = class {
22261
22637
 
22262
22638
  // src/services/timelockSettlementService.ts
22263
22639
  var import_kit17 = require("@solana/kit");
22264
- var import_web334 = require("@solana/web3.js");
22265
- var import_common58 = __toESM(require_dist());
22266
- var ZERO_PUBKEY = import_web334.PublicKey.default.toBase58();
22640
+ var import_web335 = require("@solana/web3.js");
22641
+ var import_common59 = __toESM(require_dist());
22642
+ var ZERO_PUBKEY = import_web335.PublicKey.default.toBase58();
22267
22643
  var CONSENSUS_SIGNER_CAPACITY = 4;
22268
22644
  var CONSENSUS_ENTRY_OFFSET = 40;
22269
22645
  var CONSENSUS_ENTRY_SIZE = 272;
@@ -22303,7 +22679,7 @@ function decodePendingConsensusSigners(data) {
22303
22679
  const signers = [];
22304
22680
  for (let i = 0; i < count; i += 1) {
22305
22681
  const start = CONSENSUS_PENDING_OFFSET + i * 32;
22306
- const signer = new import_web334.PublicKey(bytes.slice(start, start + 32)).toBase58();
22682
+ const signer = new import_web335.PublicKey(bytes.slice(start, start + 32)).toBase58();
22307
22683
  if (signer === ZERO_PUBKEY) {
22308
22684
  throw new Error(`pending consensus signer ${i} is unset`);
22309
22685
  }
@@ -22359,7 +22735,7 @@ var TimelockSettlementService = class {
22359
22735
  });
22360
22736
  const dryRun = opts.dryRun ?? false;
22361
22737
  const now = opts.now ?? await this.chainTime();
22362
- const fulfillerAddress = (0, import_common58.fromWeb3Pk)(fulfiller.publicKey);
22738
+ const fulfillerAddress = (0, import_common59.fromWeb3Pk)(fulfiller.publicKey);
22363
22739
  const allVaults = opts.vault ? [
22364
22740
  {
22365
22741
  publicKey: opts.vault,
@@ -22502,18 +22878,18 @@ var TimelockSettlementService = class {
22502
22878
 
22503
22879
  // src/services/nestWithdrawalService.ts
22504
22880
  var import_kit18 = require("@solana/kit");
22505
- var import_spl_token21 = require("@solana/spl-token");
22506
- var import_web335 = require("@solana/web3.js");
22507
- var import_common59 = __toESM(require_dist());
22508
- var import_nest3 = __toESM(require_dist4());
22509
- var import_nest4 = __toESM(require_dist4());
22510
- var NestOftProgram = new import_web335.PublicKey(
22881
+ var import_spl_token22 = require("@solana/spl-token");
22882
+ var import_web336 = require("@solana/web3.js");
22883
+ var import_common60 = __toESM(require_dist());
22884
+ var import_nest3 = __toESM(require_dist3());
22885
+ var import_nest4 = __toESM(require_dist3());
22886
+ var NestOftProgram = new import_web336.PublicKey(
22511
22887
  "ChEfPd3RzLeYiRwp1K9evimmaFSd6DV1S4Mv5q5Aj1th"
22512
22888
  );
22513
- var NestOftStore = new import_web335.PublicKey(
22889
+ var NestOftStore = new import_web336.PublicKey(
22514
22890
  "k8mJj8Gyw2gFAqut21AFVUUZhxb4RVDMnb4PrSYiDhV"
22515
22891
  );
22516
- var UsdcMint = new import_web335.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
22892
+ var UsdcMint = new import_web336.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
22517
22893
  var NestPerenaComposer = Buffer.from(
22518
22894
  "000000000000000000000000908dcb5531691c2124c54e30bb645cf11647090d",
22519
22895
  "hex"
@@ -22530,7 +22906,7 @@ async function buildNestWithdrawalRequest(args) {
22530
22906
  return decodeNestWithdrawalRequest({ ...args, txBase64 });
22531
22907
  }
22532
22908
  async function decodeNestWithdrawalRequest(args) {
22533
- const transaction = import_web335.VersionedTransaction.deserialize(
22909
+ const transaction = import_web336.VersionedTransaction.deserialize(
22534
22910
  Buffer.from(args.txBase64, "base64")
22535
22911
  );
22536
22912
  const message2 = transaction.message;
@@ -22551,19 +22927,19 @@ async function decodeNestWithdrawalRequest(args) {
22551
22927
  return value;
22552
22928
  })
22553
22929
  );
22554
- const decoded = import_web335.TransactionMessage.decompile(message2, {
22930
+ const decoded = import_web336.TransactionMessage.decompile(message2, {
22555
22931
  addressLookupTableAccounts: tables
22556
22932
  });
22557
- const nestMint = new import_web335.PublicKey(NEST_RWA_SHARE_MINT);
22558
- const sourceAta = (0, import_spl_token21.getAssociatedTokenAddressSync)(nestMint, args.owner, true);
22559
- const usdcAta = (0, import_spl_token21.getAssociatedTokenAddressSync)(UsdcMint, args.owner, true);
22933
+ const nestMint = new import_web336.PublicKey(NEST_RWA_SHARE_MINT);
22934
+ const sourceAta = (0, import_spl_token22.getAssociatedTokenAddressSync)(nestMint, args.owner, true);
22935
+ const usdcAta = (0, import_spl_token22.getAssociatedTokenAddressSync)(UsdcMint, args.owner, true);
22560
22936
  const instructions2 = decoded.instructions.filter(
22561
- (ix) => !ix.programId.equals(import_web335.ComputeBudgetProgram.programId)
22937
+ (ix) => !ix.programId.equals(import_web336.ComputeBudgetProgram.programId)
22562
22938
  );
22563
22939
  let sends = 0;
22564
22940
  for (const ix of instructions2) {
22565
- if (ix.programId.equals(import_spl_token21.ASSOCIATED_TOKEN_PROGRAM_ID)) {
22566
- if (ix.data.length !== 1 || ix.data[0] !== 1 || !ix.keys[0]?.pubkey.equals(args.owner) || !ix.keys[1]?.pubkey.equals(usdcAta) || !ix.keys[2]?.pubkey.equals(args.owner) || !ix.keys[3]?.pubkey.equals(UsdcMint) || !ix.keys[5]?.pubkey.equals(import_spl_token21.TOKEN_PROGRAM_ID)) {
22941
+ if (ix.programId.equals(import_spl_token22.ASSOCIATED_TOKEN_PROGRAM_ID)) {
22942
+ if (ix.data.length !== 1 || ix.data[0] !== 1 || !ix.keys[0]?.pubkey.equals(args.owner) || !ix.keys[1]?.pubkey.equals(usdcAta) || !ix.keys[2]?.pubkey.equals(args.owner) || !ix.keys[3]?.pubkey.equals(UsdcMint) || !ix.keys[5]?.pubkey.equals(import_spl_token22.TOKEN_PROGRAM_ID)) {
22567
22943
  throw new Error("Unexpected token account creation in Nest withdrawal");
22568
22944
  }
22569
22945
  continue;
@@ -22580,13 +22956,137 @@ async function decodeNestWithdrawalRequest(args) {
22580
22956
  if (sends !== 1)
22581
22957
  throw new Error("Nest withdrawal must contain exactly one OFT send");
22582
22958
  return {
22583
- instructions: instructions2.map(import_common59.toKitInstruction),
22959
+ instructions: instructions2.map(import_common60.toKitInstruction),
22584
22960
  lookupTables: tables.map((table) => (0, import_kit18.address)(table.key.toBase58()))
22585
22961
  };
22586
22962
  }
22587
22963
 
22964
+ // src/services/nestDepositService.ts
22965
+ var import_kit19 = require("@solana/kit");
22966
+ var import_spl_token23 = require("@solana/spl-token");
22967
+ var import_web337 = require("@solana/web3.js");
22968
+ var import_common61 = __toESM(require_dist());
22969
+ var import_nest5 = __toESM(require_dist3());
22970
+ var Usdc = new import_web337.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
22971
+ var Messenger = new import_web337.PublicKey("CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe");
22972
+ var Transmitter = new import_web337.PublicKey(
22973
+ "CCTPV2Sm4AdWt5296sk4P66VBZ7bEhcARwFaaS9YPbeC"
22974
+ );
22975
+ var Router = Buffer.from(
22976
+ "0000000000000000000000007de01896d36bea9cf072ac64e41685418941d8be",
22977
+ "hex"
22978
+ );
22979
+ var Composer = Buffer.from("908dcb5531691c2124c54e30bb645cf11647090d", "hex");
22980
+ var BurnWithHook = Buffer.from([111, 245, 62, 131, 204, 108, 223, 155]);
22981
+ var PerenaAssetId = Buffer.from(
22982
+ "355750bed2d05a1eb92ab578335cc3ea6d572dd5f57a086088c68667f11e50d2",
22983
+ "hex"
22984
+ );
22985
+ var MintAndSend = Buffer.from("fe030ec4", "hex");
22986
+ async function buildNestDepositRequest(args) {
22987
+ if (args.rawAmountUsdc <= 0n || args.rawAmountUsdc > BigInt(Number.MAX_SAFE_INTEGER)) {
22988
+ throw new Error(
22989
+ "Nest deposit must be a positive, safely representable USDC base-unit amount"
22990
+ );
22991
+ }
22992
+ const options = args.apiOptions ?? {};
22993
+ const response = await (options.fetchFn ?? fetch)(
22994
+ `${(options.baseUrl ?? import_nest5.NEST_API_BASE_URL).replace(
22995
+ /\/$/,
22996
+ ""
22997
+ )}/solana/nest/mint/build-tx`,
22998
+ {
22999
+ method: "POST",
23000
+ headers: { "Content-Type": "application/json" },
23001
+ signal: options.signal,
23002
+ body: JSON.stringify({
23003
+ rawAmountUsdc: Number(args.rawAmountUsdc),
23004
+ receiver: args.owner.toBase58(),
23005
+ nestVaultSlug: NEST_VAULT_SLUG,
23006
+ finality: "standard"
23007
+ })
23008
+ }
23009
+ );
23010
+ const payload = await response.json().catch(() => null);
23011
+ if (!response.ok)
23012
+ throw new Error(
23013
+ `Nest deposit API (${response.status}): ${typeof payload?.error === "string" ? payload.error : response.statusText}`
23014
+ );
23015
+ if (typeof payload?.data?.txBase64 !== "string")
23016
+ throw new Error("Nest API returned no deposit transaction");
23017
+ return decodeNestDepositRequest({ ...args, txBase64: payload.data.txBase64 });
23018
+ }
23019
+ async function decodeNestDepositRequest(args) {
23020
+ if (args.rawAmountUsdc <= 0n || args.rawAmountUsdc > BigInt(Number.MAX_SAFE_INTEGER)) {
23021
+ throw new Error(
23022
+ "Nest deposit must be a positive, safely representable USDC base-unit amount"
23023
+ );
23024
+ }
23025
+ const message2 = import_web337.VersionedTransaction.deserialize(
23026
+ Buffer.from(args.txBase64, "base64")
23027
+ ).message;
23028
+ if (!message2.staticAccountKeys[0].equals(args.owner))
23029
+ throw new Error("Nest deposit payer must be the manager");
23030
+ const tables = await Promise.all(
23031
+ message2.addressTableLookups.map(async (lookup) => {
23032
+ const { value } = await args.connection.getAddressLookupTable(
23033
+ lookup.accountKey
23034
+ );
23035
+ if (!value)
23036
+ throw new Error(`Nest lookup table not found: ${lookup.accountKey}`);
23037
+ return value;
23038
+ })
23039
+ );
23040
+ const instructions2 = import_web337.TransactionMessage.decompile(message2, {
23041
+ addressLookupTableAccounts: tables
23042
+ }).instructions;
23043
+ const shareMint = new import_web337.PublicKey(NEST_RWA_SHARE_MINT);
23044
+ const shareAta = (0, import_spl_token23.getAssociatedTokenAddressSync)(shareMint, args.owner, true);
23045
+ const usdcAta = (0, import_spl_token23.getAssociatedTokenAddressSync)(Usdc, args.owner, true);
23046
+ let burn;
23047
+ for (const ix of instructions2) {
23048
+ if (ix.programId.equals(import_web337.ComputeBudgetProgram.programId)) continue;
23049
+ if (ix.programId.equals(import_spl_token23.ASSOCIATED_TOKEN_PROGRAM_ID)) {
23050
+ if (ix.data.length !== 1 || ix.data[0] !== 1 || !ix.keys[0]?.pubkey.equals(args.owner) || !ix.keys[1]?.pubkey.equals(shareAta) || !ix.keys[2]?.pubkey.equals(args.owner) || !ix.keys[3]?.pubkey.equals(shareMint) || !ix.keys[4]?.pubkey.equals(import_web337.SystemProgram.programId) || !ix.keys[5]?.pubkey.equals(import_spl_token23.TOKEN_PROGRAM_ID))
23051
+ throw new Error("Unexpected Nest deposit token account creation");
23052
+ continue;
23053
+ }
23054
+ const d = ix.data;
23055
+ const matches = (index, key) => ix.keys[index]?.pubkey.equals(key);
23056
+ if (burn || !ix.programId.equals(Messenger) || ix.keys.length !== 18 || d.length < 316 || !d.subarray(0, 8).equals(BurnWithHook) || d.readBigUInt64LE(8) !== args.rawAmountUsdc || d.readUInt32LE(16) !== 22 || !d.subarray(20, 52).equals(Router) || !d.subarray(52, 84).equals(Router) || d.readBigUInt64LE(84) !== 0n || d.readUInt32LE(92) !== 2e3 || d.readUInt32LE(96) !== d.length - 100 || !d.subarray(100, 120).equals(Composer) || !d.subarray(120, 124).equals(MintAndSend) || !d.subarray(124, 156).equals(PerenaAssetId) || BigInt(`0x${d.subarray(156, 188).toString("hex")}`) !== args.rawAmountUsdc || BigInt(`0x${d.subarray(188, 220).toString("hex")}`) !== 128n || !d.subarray(220, 252).equals(Buffer.concat([Buffer.alloc(12), Composer])) || BigInt(`0x${d.subarray(252, 284).toString("hex")}`) !== 30168n || !d.subarray(284, 316).equals(args.owner.toBuffer()) || !matches(0, args.owner) || !matches(3, usdcAta) || !matches(10, Usdc) || !matches(12, Transmitter) || !matches(13, Messenger) || !matches(14, import_spl_token23.TOKEN_PROGRAM_ID) || !matches(15, import_web337.SystemProgram.programId) || !matches(17, Messenger) || ![0, 1, 11].every((index) => ix.keys[index].isSigner) || ix.keys.some(
23057
+ (meta, index) => meta.isSigner && ![0, 1, 11].includes(index)
23058
+ )) {
23059
+ throw new Error(
23060
+ "Unexpected Nest deposit instruction, amount, or recipient"
23061
+ );
23062
+ }
23063
+ burn = ix;
23064
+ }
23065
+ if (!burn) throw new Error("Nest deposit must contain one CCTP burn");
23066
+ const eventKey = burn.keys[11].pubkey;
23067
+ if (eventKey.equals(args.owner) || burn.keys.some(
23068
+ (meta, index) => index !== 11 && meta.pubkey.equals(eventKey)
23069
+ )) {
23070
+ throw new Error("Nest deposit event signer must be a separate account");
23071
+ }
23072
+ burn.keys[1] = { pubkey: args.owner, isSigner: true, isWritable: true };
23073
+ return {
23074
+ instructions: [
23075
+ (0, import_spl_token23.createAssociatedTokenAccountIdempotentInstruction)(
23076
+ args.owner,
23077
+ shareAta,
23078
+ args.owner,
23079
+ shareMint
23080
+ ),
23081
+ burn
23082
+ ].map(import_common61.toKitInstruction),
23083
+ lookupTables: tables.map((table) => (0, import_kit19.address)(table.key.toBase58())),
23084
+ ephemeralSignerKeys: [eventKey]
23085
+ };
23086
+ }
23087
+
22588
23088
  // src/index.ts
22589
- var import_common60 = __toESM(require_dist());
23089
+ var import_common62 = __toESM(require_dist());
22590
23090
  // Annotate the CommonJS export names for ESM import in node:
22591
23091
  0 && (module.exports = {
22592
23092
  ASSET_DECIMALS,
@@ -22624,6 +23124,7 @@ var import_common60 = __toESM(require_dist());
22624
23124
  DEFAULT_REBALANCE_BAND_BPS,
22625
23125
  DEFAULT_SLIPPAGE_BPS,
22626
23126
  DEFAULT_TARGET_LOCAL_BPS,
23127
+ DEFAULT_TARGET_LOCAL_USDC_TVL_BPS,
22627
23128
  DEFAULT_VAULT_ID,
22628
23129
  DisableCircuitBreakerBuilder,
22629
23130
  DistributeIncentiveBuilder,
@@ -22651,6 +23152,8 @@ var import_common60 = __toESM(require_dist());
22651
23152
  LOCAL_PROTOCOL_ADMIN,
22652
23153
  LargeBalanceChangeError,
22653
23154
  LivePriceSource,
23155
+ MANAGER_WALLET_NAV_DROP_TRIGGER_BPS,
23156
+ MANAGER_WALLET_NAV_TOLERANCE_BPS,
22654
23157
  MAX_APY_ANCHOR_WINDOW_SECS,
22655
23158
  MAX_BALANCE_CHANGE_BPS,
22656
23159
  MAX_CONSENSUS_SIGNERS,
@@ -22683,6 +23186,7 @@ var import_common60 = __toESM(require_dist());
22683
23186
  RemoveAssetHoldingBuilder,
22684
23187
  ReportIncentiveV3Builder,
22685
23188
  RequestJuniorTrancheWithdrawBuilder,
23189
+ RpcManagerWalletBalanceSource,
22686
23190
  SHARE_DECIMALS,
22687
23191
  SYSTEM_PROGRAM,
22688
23192
  SetAssetPriceOracleBuilder,
@@ -22722,6 +23226,7 @@ var import_common60 = __toESM(require_dist());
22722
23226
  VaultClient,
22723
23227
  VaultQuoteClient,
22724
23228
  VaultReallocationBuilder,
23229
+ WITHDRAWABLE_RESERVE_FLOOR_BPS,
22725
23230
  WithdrawalQueueService,
22726
23231
  accountingUnitPriceToUsd,
22727
23232
  addCashflowUpdate,
@@ -22731,8 +23236,10 @@ var import_common60 = __toESM(require_dist());
22731
23236
  assertNoUnconfirmedYieldPayments,
22732
23237
  buildHoldingUpdate,
22733
23238
  buildMarginfiWithdrawInteraction,
23239
+ buildNestDepositRequest,
22734
23240
  buildNestWithdrawalRequest,
22735
23241
  buildUpdates,
23242
+ candidateGrossNav,
22736
23243
  coerceBool,
22737
23244
  collectSamples,
22738
23245
  confirmYieldPayment,
@@ -22744,6 +23251,7 @@ var import_common60 = __toESM(require_dist());
22744
23251
  createVaultClient,
22745
23252
  createYieldPayment,
22746
23253
  dateToStr,
23254
+ decodeNestDepositRequest,
22747
23255
  decodeNestWithdrawalRequest,
22748
23256
  decodePendingConsensusSigners,
22749
23257
  defaultKeypairPath,
@@ -22791,6 +23299,7 @@ var import_common60 = __toESM(require_dist());
22791
23299
  loadKeypair,
22792
23300
  logProspectiveApy,
22793
23301
  makeProvider,
23302
+ managerReconciliationStateKey,
22794
23303
  mintTokensTo,
22795
23304
  mints,
22796
23305
  mostFrequent,
@@ -22798,9 +23307,11 @@ var import_common60 = __toESM(require_dist());
22798
23307
  planRebalance,
22799
23308
  prepareSquadsProposalUpload,
22800
23309
  prepareVaultTransaction,
23310
+ previousPhysicalNav,
22801
23311
  priceInAccountingUnit,
22802
23312
  readI64LE,
22803
23313
  readSplMintSupply,
23314
+ reconcileManagerWalletBalances,
22804
23315
  refreshLiveOraclePrices,
22805
23316
  resolveExternalWithdraw,
22806
23317
  resolveKeypairPath,