@epicentral/sos-sdk 0.5.0-alpha.8 → 0.6.1-alpha

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.

Potentially problematic release.


This version of @epicentral/sos-sdk might be problematic. Click here for more details.

package/long/builders.ts CHANGED
@@ -17,10 +17,15 @@ import {
17
17
  type RemainingAccountInput,
18
18
  } from "../shared/remaining-accounts";
19
19
  import type { OptionType } from "../generated/types";
20
- import { getCreateAssociatedTokenIdempotentInstructionWithAddress, NATIVE_MINT } from "../wsol/instructions";
21
- import { fetchOptionPool } from "../accounts/fetchers";
20
+ import {
21
+ getCloseAccountInstruction,
22
+ getCreateAssociatedTokenIdempotentInstructionWithAddress,
23
+ NATIVE_MINT,
24
+ } from "../wsol/instructions";
25
+ import { fetchMarketDataAccount, fetchOptionPool } from "../accounts/fetchers";
22
26
  import { getBuyFromPoolRemainingAccounts } from "./remaining-accounts";
23
27
  import { fetchWriterPositionsForPool } from "../accounts/list";
28
+ import bs58 from "bs58";
24
29
 
25
30
  export interface BuildBuyFromPoolParams {
26
31
  optionPool: AddressLike;
@@ -28,7 +33,7 @@ export interface BuildBuyFromPoolParams {
28
33
  longMint: AddressLike;
29
34
  underlyingMint: AddressLike;
30
35
  marketData: AddressLike;
31
- priceUpdate: AddressLike;
36
+ switchboardFeed: AddressLike;
32
37
  buyer: AddressLike;
33
38
  buyerPaymentAccount: AddressLike;
34
39
  escrowLongAccount: AddressLike;
@@ -49,7 +54,7 @@ export interface BuildCloseLongToPoolParams {
49
54
  escrowLongAccount: AddressLike;
50
55
  premiumVault: AddressLike;
51
56
  marketData: AddressLike;
52
- priceUpdate: AddressLike;
57
+ switchboardFeed: AddressLike;
53
58
  buyer: AddressLike;
54
59
  buyerLongAccount: AddressLike;
55
60
  buyerPayoutAccount: AddressLike;
@@ -58,6 +63,16 @@ export interface BuildCloseLongToPoolParams {
58
63
  minPayoutAmount: bigint | number;
59
64
  buyerPosition?: AddressLike;
60
65
  omlpVault?: AddressLike;
66
+ /**
67
+ * When true, appends an SPL CloseAccount to close the buyer's LONG token account after close_long_to_pool (reclaim rent).
68
+ * Set to true only when closing the entire position; for partial closes the LONG ATA still holds remaining tokens.
69
+ */
70
+ closeLongTokenAccount?: boolean;
71
+ /**
72
+ * When true and underlying is WSOL, appends an SPL CloseAccount to unwrap the payout ATA so the buyer receives native SOL.
73
+ * Ignored when underlyingMint is not WSOL.
74
+ */
75
+ unwrapPayoutSol?: boolean;
61
76
  remainingAccounts?: RemainingAccountInput[];
62
77
  }
63
78
 
@@ -73,7 +88,7 @@ export async function buildBuyFromPoolInstruction(
73
88
  longMint: toAddress(params.longMint),
74
89
  underlyingMint: toAddress(params.underlyingMint),
75
90
  marketData: toAddress(params.marketData),
76
- priceUpdate: toAddress(params.priceUpdate),
91
+ switchboardFeed: toAddress(params.switchboardFeed),
77
92
  buyer: toAddress(params.buyer) as any,
78
93
  buyerPosition: params.buyerPosition ? toAddress(params.buyerPosition) : undefined,
79
94
  buyerOptionAccount: params.buyerOptionAccount
@@ -120,7 +135,7 @@ export interface BuildBuyFromPoolTransactionWithDerivationParams {
120
135
  expirationDate: bigint | number;
121
136
  buyer: AddressLike;
122
137
  buyerPaymentAccount: AddressLike;
123
- priceUpdate: AddressLike;
138
+ switchboardFeed?: AddressLike;
124
139
  quantity: bigint | number;
125
140
  premiumAmount: bigint | number;
126
141
  rpc: KitRpc;
@@ -198,13 +213,24 @@ export async function buildBuyFromPoolTransactionWithDerivation(
198
213
  : deriveAssociatedTokenAddress(params.buyer, resolved.longMint),
199
214
  ]);
200
215
 
216
+ const marketDataAccount = await fetchMarketDataAccount(params.rpc, resolved.marketData);
217
+ invariant(
218
+ !!marketDataAccount,
219
+ "Market data account not found for resolved option market."
220
+ );
221
+ const switchboardFeed =
222
+ params.switchboardFeed ??
223
+ bs58.encode(
224
+ Array.from(marketDataAccount.switchboardFeedId as unknown as Uint8Array)
225
+ );
226
+
201
227
  return buildBuyFromPoolTransaction({
202
228
  optionPool: resolved.optionPool,
203
229
  optionAccount: resolved.optionAccount,
204
230
  longMint: resolved.longMint,
205
231
  underlyingMint: resolved.underlyingMint!,
206
232
  marketData: resolved.marketData,
207
- priceUpdate: params.priceUpdate,
233
+ switchboardFeed,
208
234
  buyer: params.buyer,
209
235
  buyerPaymentAccount: params.buyerPaymentAccount,
210
236
  escrowLongAccount: resolved.escrowLongAccount!,
@@ -292,13 +318,24 @@ export async function buildBuyFromPoolMarketOrderTransactionWithDerivation(
292
318
  const maxPremiumAmount = BigInt(params.quotedPremiumTotal) + slippageBuffer;
293
319
  assertPositiveAmount(maxPremiumAmount, "maxPremiumAmount");
294
320
 
321
+ const marketDataAccount = await fetchMarketDataAccount(params.rpc, resolved.marketData);
322
+ invariant(
323
+ !!marketDataAccount,
324
+ "Market data account not found for resolved option market."
325
+ );
326
+ const switchboardFeed =
327
+ params.switchboardFeed ??
328
+ bs58.encode(
329
+ Array.from(marketDataAccount.switchboardFeedId as unknown as Uint8Array)
330
+ );
331
+
295
332
  return buildBuyFromPoolTransaction({
296
333
  optionPool: resolved.optionPool,
297
334
  optionAccount: resolved.optionAccount,
298
335
  longMint: resolved.longMint,
299
336
  underlyingMint: refetchedPool.underlyingMint,
300
337
  marketData: resolved.marketData,
301
- priceUpdate: params.priceUpdate,
338
+ switchboardFeed,
302
339
  buyer: params.buyer,
303
340
  buyerPaymentAccount: params.buyerPaymentAccount,
304
341
  escrowLongAccount: refetchedPool.escrowLongAccount,
@@ -329,7 +366,7 @@ export async function buildCloseLongToPoolInstruction(
329
366
  escrowLongAccount: toAddress(params.escrowLongAccount),
330
367
  premiumVault: toAddress(params.premiumVault),
331
368
  marketData: toAddress(params.marketData),
332
- priceUpdate: toAddress(params.priceUpdate),
369
+ switchboardFeed: toAddress(params.switchboardFeed),
333
370
  buyer: toAddress(params.buyer) as any,
334
371
  buyerLongAccount: toAddress(params.buyerLongAccount),
335
372
  buyerPayoutAccount: toAddress(params.buyerPayoutAccount),
@@ -347,7 +384,32 @@ export async function buildCloseLongToPoolTransaction(
347
384
  params: BuildCloseLongToPoolParams
348
385
  ): Promise<BuiltTransaction> {
349
386
  const instruction = await buildCloseLongToPoolInstruction(params);
350
- return { instructions: [instruction] };
387
+ const instructions = [instruction];
388
+
389
+ if (params.closeLongTokenAccount === true) {
390
+ instructions.push(
391
+ getCloseAccountInstruction(
392
+ params.buyerLongAccount,
393
+ params.buyer,
394
+ params.buyer
395
+ )
396
+ );
397
+ }
398
+
399
+ const shouldUnwrapPayout =
400
+ params.unwrapPayoutSol === true &&
401
+ toAddress(params.underlyingMint) === toAddress(NATIVE_MINT);
402
+ if (shouldUnwrapPayout) {
403
+ instructions.push(
404
+ getCloseAccountInstruction(
405
+ params.buyerPayoutAccount,
406
+ params.buyer,
407
+ params.buyer
408
+ )
409
+ );
410
+ }
411
+
412
+ return { instructions };
351
413
  }
352
414
 
353
415
  export interface BuildCloseLongToPoolTransactionWithDerivationParams {
@@ -358,13 +420,23 @@ export interface BuildCloseLongToPoolTransactionWithDerivationParams {
358
420
  buyer: AddressLike;
359
421
  buyerLongAccount: AddressLike;
360
422
  buyerPayoutAccount: AddressLike;
361
- priceUpdate: AddressLike;
423
+ switchboardFeed?: AddressLike;
362
424
  quantity: bigint | number;
363
425
  minPayoutAmount: bigint | number;
364
426
  rpc: KitRpc;
365
427
  programId?: AddressLike;
366
428
  buyerPosition?: AddressLike;
367
429
  omlpVault?: AddressLike;
430
+ /**
431
+ * When true (default), appends CloseAccount for the buyer's LONG token account after close_long_to_pool.
432
+ * Set to false when doing a partial close (LONG ATA still holds remaining tokens).
433
+ */
434
+ closeLongTokenAccount?: boolean;
435
+ /**
436
+ * When true (default for WSOL underlying), appends CloseAccount to unwrap payout WSOL ATA to native SOL.
437
+ * Only applies when option underlying is WSOL.
438
+ */
439
+ unwrapPayoutSol?: boolean;
368
440
  remainingAccounts?: RemainingAccountInput[];
369
441
  }
370
442
 
@@ -396,6 +468,23 @@ export async function buildCloseLongToPoolTransactionWithDerivation(
396
468
  params.programId
397
469
  ))[0];
398
470
 
471
+ const isWsolUnderlying =
472
+ toAddress(resolved.underlyingMint!) === toAddress(NATIVE_MINT);
473
+ const closeLongTokenAccount =
474
+ params.closeLongTokenAccount !== false;
475
+ const unwrapPayoutSol =
476
+ params.unwrapPayoutSol !== false && isWsolUnderlying;
477
+ const marketDataAccount = await fetchMarketDataAccount(params.rpc, resolved.marketData);
478
+ invariant(
479
+ !!marketDataAccount,
480
+ "Market data account not found for resolved option market."
481
+ );
482
+ const switchboardFeed =
483
+ params.switchboardFeed ??
484
+ bs58.encode(
485
+ Array.from(marketDataAccount.switchboardFeedId as unknown as Uint8Array)
486
+ );
487
+
399
488
  return buildCloseLongToPoolTransaction({
400
489
  optionPool: resolved.optionPool,
401
490
  optionAccount: resolved.optionAccount,
@@ -405,7 +494,7 @@ export async function buildCloseLongToPoolTransactionWithDerivation(
405
494
  escrowLongAccount: resolved.escrowLongAccount!,
406
495
  premiumVault: resolved.premiumVault!,
407
496
  marketData: resolved.marketData,
408
- priceUpdate: params.priceUpdate,
497
+ switchboardFeed,
409
498
  buyer: params.buyer,
410
499
  buyerLongAccount: params.buyerLongAccount,
411
500
  buyerPayoutAccount: params.buyerPayoutAccount,
@@ -414,6 +503,8 @@ export async function buildCloseLongToPoolTransactionWithDerivation(
414
503
  minPayoutAmount: params.minPayoutAmount,
415
504
  buyerPosition,
416
505
  omlpVault: params.omlpVault,
506
+ closeLongTokenAccount,
507
+ unwrapPayoutSol,
417
508
  remainingAccounts: params.remainingAccounts,
418
509
  });
419
510
  }
package/long/exercise.ts CHANGED
@@ -8,7 +8,7 @@ export interface BuildOptionExerciseParams {
8
8
  positionAccount: AddressLike;
9
9
  marketData: AddressLike;
10
10
  underlyingMint: AddressLike;
11
- priceUpdate: AddressLike;
11
+ switchboardFeed: AddressLike;
12
12
  buyerPaymentAccount: AddressLike;
13
13
  makerCollateralAccount: AddressLike;
14
14
  escrowState: AddressLike;
@@ -30,7 +30,7 @@ export function buildOptionExerciseInstruction(
30
30
  positionAccount: toAddress(params.positionAccount),
31
31
  marketData: toAddress(params.marketData),
32
32
  underlyingMint: toAddress(params.underlyingMint),
33
- priceUpdate: toAddress(params.priceUpdate),
33
+ switchboardFeed: toAddress(params.switchboardFeed),
34
34
  buyerPaymentAccount: toAddress(params.buyerPaymentAccount),
35
35
  makerCollateralAccount: toAddress(params.makerCollateralAccount),
36
36
  escrowState: toAddress(params.escrowState),
package/omlp/builders.ts CHANGED
@@ -6,6 +6,7 @@ import type { Instruction } from "@solana/kit";
6
6
  import { toAddress } from "../client/program";
7
7
  import type { AddressLike, BuiltTransaction } from "../client/types";
8
8
  import { assertPositiveAmount } from "../shared/amounts";
9
+ import { getCloseAccountInstruction, NATIVE_MINT } from "../wsol/instructions";
9
10
 
10
11
  export interface BuildDepositToPositionParams {
11
12
  vault: AddressLike;
@@ -23,6 +24,8 @@ export interface BuildWithdrawFromPositionParams {
23
24
  lender: AddressLike;
24
25
  amount: bigint | number;
25
26
  position?: AddressLike;
27
+ unwrapSol?: boolean;
28
+ vaultMint?: AddressLike;
26
29
  }
27
30
 
28
31
  export async function buildDepositToPositionInstruction(
@@ -69,6 +72,23 @@ export async function buildWithdrawFromPositionInstruction(
69
72
  export async function buildWithdrawFromPositionTransaction(
70
73
  params: BuildWithdrawFromPositionParams
71
74
  ): Promise<BuiltTransaction> {
72
- const instruction = await buildWithdrawFromPositionInstruction(params);
73
- return { instructions: [instruction] };
75
+ const withdrawInstruction = await buildWithdrawFromPositionInstruction(params);
76
+ const instructions: Instruction<string>[] = [withdrawInstruction];
77
+
78
+ const shouldUnwrapSol =
79
+ params.unwrapSol === true &&
80
+ params.vaultMint !== undefined &&
81
+ toAddress(params.vaultMint) === toAddress(NATIVE_MINT);
82
+
83
+ if (shouldUnwrapSol) {
84
+ instructions.push(
85
+ getCloseAccountInstruction(
86
+ params.lenderTokenAccount,
87
+ params.lender,
88
+ params.lender
89
+ )
90
+ );
91
+ }
92
+
93
+ return { instructions };
74
94
  }
package/omlp/service.ts CHANGED
@@ -12,10 +12,25 @@ import {
12
12
  type BuildWithdrawFromPositionParams,
13
13
  } from "./builders";
14
14
 
15
+ const INTEREST_FP_SCALE = 1_000_000_000_000n;
16
+
15
17
  function positiveDiff(a: bigint, b: bigint): bigint {
16
18
  return a > b ? a - b : 0n;
17
19
  }
18
20
 
21
+ function calculatePendingInterest(
22
+ deposited: bigint,
23
+ vaultAccInterestPerShareFp: bigint,
24
+ positionInterestIndexSnapshotFp: bigint
25
+ ): bigint {
26
+ const deltaFp = positiveDiff(
27
+ vaultAccInterestPerShareFp,
28
+ positionInterestIndexSnapshotFp
29
+ );
30
+
31
+ return (deposited * deltaFp) / INTEREST_FP_SCALE;
32
+ }
33
+
19
34
  export async function depositToPosition(
20
35
  params: BuildDepositToPositionParams
21
36
  ) {
@@ -50,14 +65,23 @@ export async function withdrawAllFromPosition(
50
65
  position.totalInterestEarned,
51
66
  position.interestClaimed
52
67
  );
53
- const userMax = position.deposited + unclaimedInterest;
68
+ const pendingInterest = calculatePendingInterest(
69
+ position.deposited,
70
+ vault.accInterestPerShareFp,
71
+ position.interestIndexSnapshotFp
72
+ );
73
+ const userMax = position.deposited + unclaimedInterest + pendingInterest;
54
74
  const poolAvailable = positiveDiff(vault.totalLiquidity, vault.totalLoans);
55
75
  const amount = userMax < poolAvailable ? userMax : poolAvailable;
56
76
  if (amount <= 0n) {
57
77
  throw new Error("No withdrawable balance available right now.");
58
78
  }
59
79
 
60
- const built = await buildWithdrawFromPositionTransaction({ ...params, amount });
80
+ const built = await buildWithdrawFromPositionTransaction({
81
+ ...params,
82
+ amount,
83
+ vaultMint: vault.mint,
84
+ });
61
85
  return { instructions: built.instructions, amount };
62
86
  }
63
87
 
@@ -83,13 +107,26 @@ export async function withdrawInterestFromPosition(
83
107
  position.totalInterestEarned,
84
108
  position.interestClaimed
85
109
  );
110
+ const pendingInterest = calculatePendingInterest(
111
+ position.deposited,
112
+ vault.accInterestPerShareFp,
113
+ position.interestIndexSnapshotFp
114
+ );
115
+ const totalClaimableInterest = unclaimedInterest + pendingInterest;
86
116
  const poolAvailable = positiveDiff(vault.totalLiquidity, vault.totalLoans);
87
- const amount = unclaimedInterest < poolAvailable ? unclaimedInterest : poolAvailable;
117
+ const amount =
118
+ totalClaimableInterest < poolAvailable
119
+ ? totalClaimableInterest
120
+ : poolAvailable;
88
121
  if (amount <= 0n) {
89
122
  throw new Error("No claimable interest available right now.");
90
123
  }
91
124
 
92
- const built = await buildWithdrawFromPositionTransaction({ ...params, amount });
125
+ const built = await buildWithdrawFromPositionTransaction({
126
+ ...params,
127
+ amount,
128
+ vaultMint: vault.mint,
129
+ });
93
130
  return { instructions: built.instructions, amount };
94
131
  }
95
132
 
@@ -0,0 +1,56 @@
1
+ import type { Address } from "@solana/kit";
2
+ import bs58 from "bs58";
3
+ import { toAddress } from "../client/program";
4
+ import type { AddressLike, KitRpc } from "../client/types";
5
+ import { fetchMarketDataAccount } from "../accounts/fetchers";
6
+ import { invariant } from "../shared/errors";
7
+
8
+ export async function resolveSwitchboardFeedFromMarketData(
9
+ rpc: KitRpc,
10
+ marketData: AddressLike
11
+ ): Promise<Address> {
12
+ const account = await fetchMarketDataAccount(rpc, marketData);
13
+ invariant(!!account, "Market data account not found.");
14
+ return toAddress(
15
+ bs58.encode(
16
+ Array.from(account.switchboardFeedId as unknown as Uint8Array)
17
+ )
18
+ );
19
+ }
20
+
21
+ export interface SwitchboardPullFeedLike<TInstruction = unknown, TLookupTable = unknown> {
22
+ fetchUpdateIx(args: {
23
+ crossbarClient: unknown;
24
+ chain?: "solana";
25
+ network?: "devnet" | "mainnet";
26
+ }): Promise<[TInstruction | null, unknown, unknown, TLookupTable[]]>;
27
+ }
28
+
29
+ export interface BuildSwitchboardPullFeedUpdateParams<
30
+ TInstruction = unknown,
31
+ TLookupTable = unknown,
32
+ > {
33
+ pullFeed: SwitchboardPullFeedLike<TInstruction, TLookupTable>;
34
+ crossbarClient: unknown;
35
+ chain?: "solana";
36
+ network?: "devnet" | "mainnet";
37
+ }
38
+
39
+ export async function buildSwitchboardPullFeedUpdate<
40
+ TInstruction = unknown,
41
+ TLookupTable = unknown,
42
+ >(
43
+ params: BuildSwitchboardPullFeedUpdateParams<TInstruction, TLookupTable>
44
+ ): Promise<{ updateInstructions: TInstruction[]; lookupTables: TLookupTable[] }> {
45
+ const [pullIx, _responses, _success, luts] = await params.pullFeed.fetchUpdateIx({
46
+ crossbarClient: params.crossbarClient,
47
+ chain: params.chain ?? "solana",
48
+ network: params.network,
49
+ });
50
+
51
+ const updateInstructions: TInstruction[] = pullIx ? [pullIx] : [];
52
+ return {
53
+ updateInstructions,
54
+ lookupTables: luts ?? [],
55
+ };
56
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicentral/sos-sdk",
3
- "version": "0.5.0-alpha.8",
3
+ "version": "0.6.1-alpha",
4
4
  "private": false,
5
5
  "description": "Solana Option Standard SDK. The frontend-first SDK for Native Options Trading on Solana. Created by Epicentral Labs.",
6
6
  "type": "module",
package/short/builders.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  import type { Instruction, TransactionSigner } from "@solana/kit";
9
9
  import { toAddress } from "../client/program";
10
10
  import type { AddressLike, BuiltTransaction, KitRpc } from "../client/types";
11
- import { fetchVault } from "../accounts/fetchers";
11
+ import { fetchMarketDataAccount, fetchVault } from "../accounts/fetchers";
12
12
  import { fetchPoolLoansByMaker } from "../accounts/list";
13
13
  import { resolveOptionAccounts } from "../accounts/resolve-option";
14
14
  import {
@@ -25,11 +25,13 @@ import {
25
25
  type RemainingAccountInput,
26
26
  } from "../shared/remaining-accounts";
27
27
  import {
28
+ getCloseAccountInstruction,
28
29
  NATIVE_MINT,
29
30
  getCreateAssociatedTokenIdempotentInstructionWithAddress,
30
31
  getWrapSOLInstructions,
31
32
  } from "../wsol/instructions";
32
33
  import { preflightUnwindWriterUnsold } from "./preflight";
34
+ import bs58 from "bs58";
33
35
 
34
36
  export interface BuildOptionMintParams {
35
37
  optionType: OptionType;
@@ -49,11 +51,8 @@ export interface BuildOptionMintParams {
49
51
  maker: AddressLike;
50
52
  makerCollateralAccount: AddressLike;
51
53
  underlyingMint: AddressLike;
52
- /**
53
- * Pyth price update account for collateral calculation.
54
- * Required to convert USD collateral requirement to token units.
55
- */
56
- priceUpdate: AddressLike;
54
+ /** Switchboard pull feed account for collateral calculation. */
55
+ switchboardFeed: AddressLike;
57
56
  longMetadataAccount?: AddressLike;
58
57
  shortMetadataAccount?: AddressLike;
59
58
  optionAccount?: AddressLike;
@@ -75,6 +74,12 @@ export interface BuildOptionMintParams {
75
74
  escrowAuthority?: AddressLike;
76
75
  escrowTokenAccount?: AddressLike;
77
76
  poolLoan?: AddressLike;
77
+ /**
78
+ * When true (default), appends an SPL CloseAccount instruction after option_mint to close the
79
+ * maker's LONG token account (reclaim rent). The program transfers all LONG to escrow, so the
80
+ * maker's LONG ATA is left with zero balance and can be closed in the same transaction.
81
+ */
82
+ closeMakerLongAccount?: boolean;
78
83
  remainingAccounts?: RemainingAccountInput[];
79
84
  }
80
85
 
@@ -193,7 +198,7 @@ export async function buildOptionMintInstruction(
193
198
  ? toAddress(params.escrowTokenAccount)
194
199
  : undefined,
195
200
  poolLoan: params.poolLoan ? toAddress(params.poolLoan) : undefined,
196
- priceUpdate: toAddress(params.priceUpdate),
201
+ switchboardFeed: toAddress(params.switchboardFeed),
197
202
  maker: toAddress(params.maker) as any,
198
203
  optionType: params.optionType,
199
204
  strikePrice: params.strikePrice,
@@ -213,7 +218,21 @@ export async function buildOptionMintTransaction(
213
218
  params: BuildOptionMintParams
214
219
  ): Promise<BuiltTransaction> {
215
220
  const instruction = await buildOptionMintInstruction(params);
216
- return { instructions: [instruction] };
221
+ const instructions: Instruction<string>[] = [instruction];
222
+
223
+ const shouldCloseMakerLong =
224
+ params.closeMakerLongAccount !== false && params.makerLongAccount != null;
225
+ if (shouldCloseMakerLong) {
226
+ instructions.push(
227
+ getCloseAccountInstruction(
228
+ params.makerLongAccount!,
229
+ params.maker,
230
+ params.maker
231
+ )
232
+ );
233
+ }
234
+
235
+ return { instructions };
217
236
  }
218
237
 
219
238
  export interface BuildOptionMintTransactionWithDerivationParams {
@@ -238,11 +257,8 @@ export interface BuildOptionMintTransactionWithDerivationParams {
238
257
  * (or underlyingMint if collateralMint is not provided).
239
258
  */
240
259
  makerCollateralAccount?: AddressLike;
241
- /**
242
- * Pyth price update account for collateral calculation.
243
- * Required to convert USD collateral requirement to token units.
244
- */
245
- priceUpdate: AddressLike;
260
+ /** Optional explicit Switchboard feed account override. */
261
+ switchboardFeed?: AddressLike;
246
262
  rpc: KitRpc;
247
263
  programId?: AddressLike;
248
264
  vault?: AddressLike;
@@ -294,6 +310,16 @@ export async function buildOptionMintTransactionWithDerivation(
294
310
  const makerCollateralAccount = params.makerCollateralAccount
295
311
  ? toAddress(params.makerCollateralAccount)
296
312
  : await deriveAssociatedTokenAddress(params.maker, collateralMint);
313
+ const marketDataAccount = await fetchMarketDataAccount(params.rpc, resolved.marketData);
314
+ invariant(
315
+ !!marketDataAccount,
316
+ "Market data account not found for resolved option market."
317
+ );
318
+ const switchboardFeed =
319
+ params.switchboardFeed ??
320
+ bs58.encode(
321
+ Array.from(marketDataAccount.switchboardFeedId as unknown as Uint8Array)
322
+ );
297
323
 
298
324
  const tx = await buildOptionMintTransaction({
299
325
  ...params,
@@ -313,6 +339,7 @@ export async function buildOptionMintTransactionWithDerivation(
313
339
  premiumVault: resolved.premiumVault,
314
340
  collateralPool: resolved.collateralPool,
315
341
  collateralVault: resolved.collateralVault,
342
+ switchboardFeed,
316
343
  vault: params.vault,
317
344
  vaultTokenAccount: params.vaultTokenAccount,
318
345
  escrowState: params.escrowState,