@epicentral/sos-sdk 0.4.0-alpha.3 → 0.5.0-alpha.2

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/README.md CHANGED
@@ -57,7 +57,7 @@ Additional modules:
57
57
 
58
58
  | Function | Description |
59
59
  |----------|-------------|
60
- | `buildOptionMintTransactionWithDerivation` | Builds option mint (write) transaction. |
60
+ | `buildOptionMintTransactionWithDerivation` | Builds option mint (write) transaction. Supports multi-collateral: use `collateralMint` to back positions with any supported asset (USDC, BTC, SOL, etc.). |
61
61
  | `buildUnwindWriterUnsoldTransactionWithDerivation` | Builds unwind unsold transaction. |
62
62
  | `buildUnwindWriterUnsoldWithLoanRepayment` | **Unwind + repay pool loans in one tx.** Use when closing unsold shorts that borrowed from OMLP. |
63
63
  | `buildSyncWriterPositionTransaction` | Syncs writer position with pool accumulators. |
@@ -88,6 +88,63 @@ Borrow/repay for writers: use `buildOptionMintTransactionWithDerivation` (with v
88
88
  | `getCreateAssociatedTokenIdempotentInstructionWithAddress` | Creates ATA if missing (idempotent). |
89
89
  | `NATIVE_MINT` | WSOL mint address. |
90
90
 
91
+ ## Multi-Collateral Settlement
92
+
93
+ The SDK supports universal multi-collateral settlement, allowing writers to use ANY supported asset as collateral for options (not just the underlying). This enables:
94
+
95
+ - **Capital Efficiency**: Writers use whatever assets they hold (USDC, BTC, SOL, BONK, etc.)
96
+ - **No Forced Conversions**: No swap fees or slippage to get the "correct" collateral
97
+ - **Lender Flexibility**: Lend any supported asset, earn yield in that asset
98
+
99
+ ### How it works
100
+
101
+ When minting an option, specify `collateralMint` to choose the backing asset:
102
+
103
+ ```ts
104
+ import {
105
+ buildOptionMintTransactionWithDerivation,
106
+ OptionType,
107
+ } from "@epicentral/sos-sdk";
108
+
109
+ // Write SOL calls backed by USDC
110
+ const tx = await buildOptionMintTransactionWithDerivation({
111
+ underlyingAsset: SOL_MINT,
112
+ optionType: OptionType.Call,
113
+ strikePrice: 150.0,
114
+ expirationDate: BigInt(1735689600),
115
+ quantity: 1_000_000, // 1 contract
116
+ underlyingMint: SOL_MINT,
117
+ underlyingSymbol: "SOL",
118
+ collateralMint: USDC_MINT, // Back with USDC instead of SOL
119
+ makerCollateralAmount: 780_000_000, // $780 (10% of $7,800)
120
+ borrowedAmount: 7_020_000_000, // $7,020 (90% borrowed)
121
+ maker: walletAddress,
122
+ rpc,
123
+ });
124
+ ```
125
+
126
+ **Key points:**
127
+ - `collateralMint` defaults to `underlyingMint` if not provided (backwards compatible)
128
+ - OMLP vault routing is based on `collateralMint` - the vault must exist for the collateral asset
129
+ - At settlement, buyers receive payout in the collateral currency that backed the position
130
+ - The `WriterPosition` account tracks `collateralMint` and `settlementMint` for each position
131
+
132
+ ### Collateral Calculation
133
+
134
+ Use `calculateRequiredCollateral` to estimate collateral needs before minting:
135
+
136
+ ```ts
137
+ import { calculateRequiredCollateral } from "@epicentral/sos-sdk";
138
+
139
+ const required = calculateRequiredCollateral(
140
+ 1_000_000n, // 1 contract in base units
141
+ 150.0, // $150 strike price
142
+ 145.23, // Current spot price (USD)
143
+ 6 // USDC decimals
144
+ );
145
+ // Returns: USDC base units needed
146
+ ```
147
+
91
148
  ## Unwind with Loan Repayment
92
149
 
93
150
  When a writer unwinds an unsold short that had borrowed from the OMLP pool, the program repays proportionally to the unwind ratio inside `unwind_writer_unsold`:
@@ -260,3 +317,28 @@ PDAs, fetchers, and builders are exported from the package root.
260
317
  ## Program Compatibility
261
318
 
262
319
  The SDK targets the Solana Option Standard program. Use `PROGRAM_ID` (or `getProgramId()`) from the package for the program address. Pass `programId` in builder params when using a different deployment.
320
+
321
+ ## Collateral Calculation Helper
322
+
323
+ The SDK exports `calculateRequiredCollateral` for pre-flight collateral estimation:
324
+
325
+ ```ts
326
+ import { calculateRequiredCollateral } from "@epicentral/sos-sdk";
327
+
328
+ const required = calculateRequiredCollateral(
329
+ 1_000_000n, // 1 contract in base units
330
+ 150.0, // $150 strike price
331
+ 145.23, // Current spot price (USD)
332
+ 9 // Token decimals (9 for SOL)
333
+ );
334
+ // Returns: token base units needed (e.g., 103_280_000_000 lamports for ~103.28 SOL)
335
+ ```
336
+
337
+ **Formula:**
338
+ ```
339
+ contracts = quantity / 1_000_000
340
+ usd_value = contracts * 100 * strike_price
341
+ collateral = (usd_value / spot_price) * 10^token_decimals
342
+ ```
343
+
344
+ This matches the on-chain formula in `Vault::calculate_required_collateral` and can be used to display required collateral to users before submitting an `option_mint` transaction.
@@ -4,7 +4,7 @@ import { PROGRAM_ID } from "./program";
4
4
  import type { KitRpc } from "./types";
5
5
 
6
6
  export const LOOKUP_TABLE_ADDRESSES: Record<"devnet" | "mainnet", Address | null> = {
7
- devnet: address("B7kctbAQDEHT8gJcqRB3Bjkv4EkxMCZecy2H6EQNLQPo"),
7
+ devnet: address("EheW9UCUDMFybVKKXh5Eyg8hgVQpVc3uBZjBpu9gai4L"),
8
8
  mainnet: null,
9
9
  };
10
10
 
@@ -62,6 +62,12 @@ export type PositionAccount = {
62
62
  isClosed: boolean;
63
63
  isExercised: boolean;
64
64
  pnl: bigint;
65
+ /**
66
+ * Collateral mint used for settlement (e.g., USDC, BTC, SOL)
67
+ * Tracks which currency the buyer will receive at exercise/close
68
+ * Matches the WriterPosition.collateral_mint of the writer(s) who filled this position
69
+ */
70
+ collateralMint: Address;
65
71
  };
66
72
 
67
73
  export type PositionAccountArgs = {
@@ -74,6 +80,12 @@ export type PositionAccountArgs = {
74
80
  isClosed: boolean;
75
81
  isExercised: boolean;
76
82
  pnl: number | bigint;
83
+ /**
84
+ * Collateral mint used for settlement (e.g., USDC, BTC, SOL)
85
+ * Tracks which currency the buyer will receive at exercise/close
86
+ * Matches the WriterPosition.collateral_mint of the writer(s) who filled this position
87
+ */
88
+ collateralMint: Address;
77
89
  };
78
90
 
79
91
  /** Gets the encoder for {@link PositionAccountArgs} account data. */
@@ -90,6 +102,7 @@ export function getPositionAccountEncoder(): FixedSizeEncoder<PositionAccountArg
90
102
  ["isClosed", getBooleanEncoder()],
91
103
  ["isExercised", getBooleanEncoder()],
92
104
  ["pnl", getI64Encoder()],
105
+ ["collateralMint", getAddressEncoder()],
93
106
  ]),
94
107
  (value) => ({ ...value, discriminator: POSITION_ACCOUNT_DISCRIMINATOR }),
95
108
  );
@@ -108,6 +121,7 @@ export function getPositionAccountDecoder(): FixedSizeDecoder<PositionAccount> {
108
121
  ["isClosed", getBooleanDecoder()],
109
122
  ["isExercised", getBooleanDecoder()],
110
123
  ["pnl", getI64Decoder()],
124
+ ["collateralMint", getAddressDecoder()],
111
125
  ]);
112
126
  }
113
127
 
@@ -183,5 +197,5 @@ export async function fetchAllMaybePositionAccount(
183
197
  }
184
198
 
185
199
  export function getPositionAccountSize(): number {
186
- return 114;
200
+ return 146;
187
201
  }
@@ -63,6 +63,16 @@ export type WriterPosition = {
63
63
  optionPool: Address;
64
64
  /** Reference to the option account */
65
65
  optionAccount: Address;
66
+ /**
67
+ * Mint used for collateral backing this position (e.g., USDC, BTC, SOL)
68
+ * Can differ from the underlying asset - enables multi-collateral system
69
+ */
70
+ collateralMint: Address;
71
+ /**
72
+ * Mint used for settlement (same as collateral_mint)
73
+ * Buyers receive payout in this currency
74
+ */
75
+ settlementMint: Address;
66
76
  /** Total contracts written (minted) by this writer */
67
77
  writtenQty: bigint;
68
78
  /** Total contracts sold to buyers (open interest from this writer) */
@@ -115,6 +125,16 @@ export type WriterPositionArgs = {
115
125
  optionPool: Address;
116
126
  /** Reference to the option account */
117
127
  optionAccount: Address;
128
+ /**
129
+ * Mint used for collateral backing this position (e.g., USDC, BTC, SOL)
130
+ * Can differ from the underlying asset - enables multi-collateral system
131
+ */
132
+ collateralMint: Address;
133
+ /**
134
+ * Mint used for settlement (same as collateral_mint)
135
+ * Buyers receive payout in this currency
136
+ */
137
+ settlementMint: Address;
118
138
  /** Total contracts written (minted) by this writer */
119
139
  writtenQty: number | bigint;
120
140
  /** Total contracts sold to buyers (open interest from this writer) */
@@ -168,6 +188,8 @@ export function getWriterPositionEncoder(): FixedSizeEncoder<WriterPositionArgs>
168
188
  ["writerAuthority", getAddressEncoder()],
169
189
  ["optionPool", getAddressEncoder()],
170
190
  ["optionAccount", getAddressEncoder()],
191
+ ["collateralMint", getAddressEncoder()],
192
+ ["settlementMint", getAddressEncoder()],
171
193
  ["writtenQty", getU64Encoder()],
172
194
  ["soldQty", getU64Encoder()],
173
195
  ["unsoldQty", getU64Encoder()],
@@ -203,6 +225,8 @@ export function getWriterPositionDecoder(): FixedSizeDecoder<WriterPosition> {
203
225
  ["writerAuthority", getAddressDecoder()],
204
226
  ["optionPool", getAddressDecoder()],
205
227
  ["optionAccount", getAddressDecoder()],
228
+ ["collateralMint", getAddressDecoder()],
229
+ ["settlementMint", getAddressDecoder()],
206
230
  ["writtenQty", getU64Decoder()],
207
231
  ["soldQty", getU64Decoder()],
208
232
  ["unsoldQty", getU64Decoder()],
@@ -299,5 +323,5 @@ export async function fetchAllMaybeWriterPosition(
299
323
  }
300
324
 
301
325
  export function getWriterPositionSize(): number {
302
- return 300;
326
+ return 364;
303
327
  }
@@ -196,6 +196,12 @@ export const OPTION_PROGRAM_ERROR__UNWIND_REPAY_WALLET_SOURCE_MISSING = 0x17c8;
196
196
  export const OPTION_PROGRAM_ERROR__UNWIND_REPAY_INSUFFICIENT_TOTAL_FUNDS = 0x17c9; // 6089
197
197
  /** InsufficientCollateralVault: Collateral vault has insufficient funds for unwind collateral return */
198
198
  export const OPTION_PROGRAM_ERROR__INSUFFICIENT_COLLATERAL_VAULT = 0x17ca; // 6090
199
+ /** InvalidVaultMint: Invalid vault mint - does not match expected collateral mint */
200
+ export const OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT = 0x17cb; // 6091
201
+ /** InvalidCollateralMint: Invalid collateral mint - not supported or no vault exists */
202
+ export const OPTION_PROGRAM_ERROR__INVALID_COLLATERAL_MINT = 0x17cc; // 6092
203
+ /** CollateralMismatch: Collateral mint mismatch - position uses different collateral type */
204
+ export const OPTION_PROGRAM_ERROR__COLLATERAL_MISMATCH = 0x17cd; // 6093
199
205
 
200
206
  export type OptionProgramError =
201
207
  | typeof OPTION_PROGRAM_ERROR__ACCOUNT_FROZEN
@@ -203,6 +209,7 @@ export type OptionProgramError =
203
209
  | typeof OPTION_PROGRAM_ERROR__ARITHMETIC_OVERFLOW
204
210
  | typeof OPTION_PROGRAM_ERROR__ARITHMETIC_UNDERFLOW
205
211
  | typeof OPTION_PROGRAM_ERROR__BATCH_SIZE_EXCEEDED
212
+ | typeof OPTION_PROGRAM_ERROR__COLLATERAL_MISMATCH
206
213
  | typeof OPTION_PROGRAM_ERROR__COLLATERAL_POOL_NOT_FOUND
207
214
  | typeof OPTION_PROGRAM_ERROR__CONTRACT_ALREADY_SETTLED
208
215
  | typeof OPTION_PROGRAM_ERROR__DIVISION_BY_ZERO
@@ -227,6 +234,7 @@ export type OptionProgramError =
227
234
  | typeof OPTION_PROGRAM_ERROR__INVALID_ACCOUNT
228
235
  | typeof OPTION_PROGRAM_ERROR__INVALID_AUTHORITY
229
236
  | typeof OPTION_PROGRAM_ERROR__INVALID_BUYER_AUTHORITY
237
+ | typeof OPTION_PROGRAM_ERROR__INVALID_COLLATERAL_MINT
230
238
  | typeof OPTION_PROGRAM_ERROR__INVALID_ESCROW_AUTHORITY
231
239
  | typeof OPTION_PROGRAM_ERROR__INVALID_ESCROW_MAKER
232
240
  | typeof OPTION_PROGRAM_ERROR__INVALID_ESCROW_MINT
@@ -248,6 +256,7 @@ export type OptionProgramError =
248
256
  | typeof OPTION_PROGRAM_ERROR__INVALID_TENOR
249
257
  | typeof OPTION_PROGRAM_ERROR__INVALID_TIME_TO_EXPIRATION
250
258
  | typeof OPTION_PROGRAM_ERROR__INVALID_UNDERLYING_PRICE
259
+ | typeof OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT
251
260
  | typeof OPTION_PROGRAM_ERROR__INVALID_VOLATILITY
252
261
  | typeof OPTION_PROGRAM_ERROR__LOW_ORACLE_PRICE_CONFIDENCE
253
262
  | typeof OPTION_PROGRAM_ERROR__MARKET_CLOSED
@@ -298,6 +307,7 @@ if (process.env.NODE_ENV !== "production") {
298
307
  [OPTION_PROGRAM_ERROR__ARITHMETIC_OVERFLOW]: `Arithmetic overflow occurred`,
299
308
  [OPTION_PROGRAM_ERROR__ARITHMETIC_UNDERFLOW]: `Arithmetic underflow occurred`,
300
309
  [OPTION_PROGRAM_ERROR__BATCH_SIZE_EXCEEDED]: `Batch size exceeds maximum allowed (10 positions)`,
310
+ [OPTION_PROGRAM_ERROR__COLLATERAL_MISMATCH]: `Collateral mint mismatch - position uses different collateral type`,
301
311
  [OPTION_PROGRAM_ERROR__COLLATERAL_POOL_NOT_FOUND]: `Collateral pool does not exist`,
302
312
  [OPTION_PROGRAM_ERROR__CONTRACT_ALREADY_SETTLED]: `Contract already settled`,
303
313
  [OPTION_PROGRAM_ERROR__DIVISION_BY_ZERO]: `Division by zero`,
@@ -322,6 +332,7 @@ if (process.env.NODE_ENV !== "production") {
322
332
  [OPTION_PROGRAM_ERROR__INVALID_ACCOUNT]: `Invalid account - does not match expected account`,
323
333
  [OPTION_PROGRAM_ERROR__INVALID_AUTHORITY]: `Invalid authority - does not match escrow authority`,
324
334
  [OPTION_PROGRAM_ERROR__INVALID_BUYER_AUTHORITY]: `Invalid buyer authority`,
335
+ [OPTION_PROGRAM_ERROR__INVALID_COLLATERAL_MINT]: `Invalid collateral mint - not supported or no vault exists`,
325
336
  [OPTION_PROGRAM_ERROR__INVALID_ESCROW_AUTHORITY]: `Invalid escrow authority`,
326
337
  [OPTION_PROGRAM_ERROR__INVALID_ESCROW_MAKER]: `Escrow state maker does not match instruction maker`,
327
338
  [OPTION_PROGRAM_ERROR__INVALID_ESCROW_MINT]: `Escrow token account mint mismatch`,
@@ -343,6 +354,7 @@ if (process.env.NODE_ENV !== "production") {
343
354
  [OPTION_PROGRAM_ERROR__INVALID_TENOR]: `Invalid loan tenor`,
344
355
  [OPTION_PROGRAM_ERROR__INVALID_TIME_TO_EXPIRATION]: `Time to expiration must be positive`,
345
356
  [OPTION_PROGRAM_ERROR__INVALID_UNDERLYING_PRICE]: `Underlying price is invalid`,
357
+ [OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT]: `Invalid vault mint - does not match expected collateral mint`,
346
358
  [OPTION_PROGRAM_ERROR__INVALID_VOLATILITY]: `Volatility must be greater than zero`,
347
359
  [OPTION_PROGRAM_ERROR__LOW_ORACLE_PRICE_CONFIDENCE]: `Oracle price confidence is too low`,
348
360
  [OPTION_PROGRAM_ERROR__MARKET_CLOSED]: `Market is closed`,
@@ -79,6 +79,7 @@ export type OptionMintInstruction<
79
79
  TAccountShortMetadataAccount extends string | AccountMeta<string> = string,
80
80
  TAccountMarketData extends string | AccountMeta<string> = string,
81
81
  TAccountUnderlyingMint extends string | AccountMeta<string> = string,
82
+ TAccountCollateralMint extends string | AccountMeta<string> = string,
82
83
  TAccountOptionPool extends string | AccountMeta<string> = string,
83
84
  TAccountEscrowLongAccount extends string | AccountMeta<string> = string,
84
85
  TAccountPremiumVault extends string | AccountMeta<string> = string,
@@ -92,6 +93,7 @@ export type OptionMintInstruction<
92
93
  TAccountEscrowAuthority extends string | AccountMeta<string> = string,
93
94
  TAccountEscrowTokenAccount extends string | AccountMeta<string> = string,
94
95
  TAccountPoolLoan extends string | AccountMeta<string> = string,
96
+ TAccountPriceUpdate extends string | AccountMeta<string> = string,
95
97
  TAccountMaker extends string | AccountMeta<string> = string,
96
98
  TAccountTokenProgram extends string | AccountMeta<string> =
97
99
  "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
@@ -138,6 +140,9 @@ export type OptionMintInstruction<
138
140
  TAccountUnderlyingMint extends string
139
141
  ? ReadonlyAccount<TAccountUnderlyingMint>
140
142
  : TAccountUnderlyingMint,
143
+ TAccountCollateralMint extends string
144
+ ? ReadonlyAccount<TAccountCollateralMint>
145
+ : TAccountCollateralMint,
141
146
  TAccountOptionPool extends string
142
147
  ? WritableAccount<TAccountOptionPool>
143
148
  : TAccountOptionPool,
@@ -177,6 +182,9 @@ export type OptionMintInstruction<
177
182
  TAccountPoolLoan extends string
178
183
  ? WritableAccount<TAccountPoolLoan>
179
184
  : TAccountPoolLoan,
185
+ TAccountPriceUpdate extends string
186
+ ? ReadonlyAccount<TAccountPriceUpdate>
187
+ : TAccountPriceUpdate,
180
188
  TAccountMaker extends string
181
189
  ? WritableSignerAccount<TAccountMaker> &
182
190
  AccountSignerMeta<TAccountMaker>
@@ -208,6 +216,7 @@ export type OptionMintInstructionData = {
208
216
  quantity: bigint;
209
217
  underlyingAsset: Address;
210
218
  underlyingSymbol: string;
219
+ collateralMint: Address;
211
220
  makerCollateralAmount: bigint;
212
221
  borrowedAmount: bigint;
213
222
  };
@@ -219,6 +228,7 @@ export type OptionMintInstructionDataArgs = {
219
228
  quantity: number | bigint;
220
229
  underlyingAsset: Address;
221
230
  underlyingSymbol: string;
231
+ collateralMint: Address;
222
232
  makerCollateralAmount: number | bigint;
223
233
  borrowedAmount: number | bigint;
224
234
  };
@@ -236,6 +246,7 @@ export function getOptionMintInstructionDataEncoder(): Encoder<OptionMintInstruc
236
246
  "underlyingSymbol",
237
247
  addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder()),
238
248
  ],
249
+ ["collateralMint", getAddressEncoder()],
239
250
  ["makerCollateralAmount", getU64Encoder()],
240
251
  ["borrowedAmount", getU64Encoder()],
241
252
  ]),
@@ -255,6 +266,7 @@ export function getOptionMintInstructionDataDecoder(): Decoder<OptionMintInstruc
255
266
  "underlyingSymbol",
256
267
  addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder()),
257
268
  ],
269
+ ["collateralMint", getAddressDecoder()],
258
270
  ["makerCollateralAmount", getU64Decoder()],
259
271
  ["borrowedAmount", getU64Decoder()],
260
272
  ]);
@@ -281,6 +293,7 @@ export type OptionMintAsyncInput<
281
293
  TAccountShortMetadataAccount extends string = string,
282
294
  TAccountMarketData extends string = string,
283
295
  TAccountUnderlyingMint extends string = string,
296
+ TAccountCollateralMint extends string = string,
284
297
  TAccountOptionPool extends string = string,
285
298
  TAccountEscrowLongAccount extends string = string,
286
299
  TAccountPremiumVault extends string = string,
@@ -294,6 +307,7 @@ export type OptionMintAsyncInput<
294
307
  TAccountEscrowAuthority extends string = string,
295
308
  TAccountEscrowTokenAccount extends string = string,
296
309
  TAccountPoolLoan extends string = string,
310
+ TAccountPriceUpdate extends string = string,
297
311
  TAccountMaker extends string = string,
298
312
  TAccountTokenProgram extends string = string,
299
313
  TAccountAssociatedTokenProgram extends string = string,
@@ -325,8 +339,14 @@ export type OptionMintAsyncInput<
325
339
  shortMetadataAccount: Address<TAccountShortMetadataAccount>;
326
340
  /** Market data account - provides baseline historical volatility for initial IV */
327
341
  marketData?: Address<TAccountMarketData>;
328
- /** Underlying asset mint (e.g., WSOL) - required for collateral and pool initialization */
342
+ /** Underlying asset mint (e.g., WSOL) - required for pricing and pool initialization */
329
343
  underlyingMint: Address<TAccountUnderlyingMint>;
344
+ /**
345
+ * Collateral mint (e.g., USDC, BTC, SOL) - Writer's choice for backing the position
346
+ * Can differ from underlying_mint - enables multi-collateral settlement
347
+ * OMLP vault routing is based on this mint
348
+ */
349
+ collateralMint: Address<TAccountCollateralMint>;
330
350
  /** Option pool - aggregated liquidity pool for this option */
331
351
  optionPool?: Address<TAccountOptionPool>;
332
352
  /** Pool's escrow for holding LONG tokens (for buyers to purchase) */
@@ -353,6 +373,11 @@ export type OptionMintAsyncInput<
353
373
  escrowTokenAccount?: Address<TAccountEscrowTokenAccount>;
354
374
  /** Pool loan account (optional - only required if borrowing) */
355
375
  poolLoan?: Address<TAccountPoolLoan>;
376
+ /**
377
+ * Pyth price update account for collateral calculation
378
+ * Required to convert USD collateral requirement to token units
379
+ */
380
+ priceUpdate: Address<TAccountPriceUpdate>;
356
381
  maker: TransactionSigner<TAccountMaker>;
357
382
  tokenProgram?: Address<TAccountTokenProgram>;
358
383
  associatedTokenProgram?: Address<TAccountAssociatedTokenProgram>;
@@ -365,6 +390,7 @@ export type OptionMintAsyncInput<
365
390
  quantity: OptionMintInstructionDataArgs["quantity"];
366
391
  underlyingAsset: OptionMintInstructionDataArgs["underlyingAsset"];
367
392
  underlyingSymbol: OptionMintInstructionDataArgs["underlyingSymbol"];
393
+ collateralMintArg: OptionMintInstructionDataArgs["collateralMint"];
368
394
  makerCollateralAmount: OptionMintInstructionDataArgs["makerCollateralAmount"];
369
395
  borrowedAmount: OptionMintInstructionDataArgs["borrowedAmount"];
370
396
  };
@@ -380,6 +406,7 @@ export async function getOptionMintInstructionAsync<
380
406
  TAccountShortMetadataAccount extends string,
381
407
  TAccountMarketData extends string,
382
408
  TAccountUnderlyingMint extends string,
409
+ TAccountCollateralMint extends string,
383
410
  TAccountOptionPool extends string,
384
411
  TAccountEscrowLongAccount extends string,
385
412
  TAccountPremiumVault extends string,
@@ -393,6 +420,7 @@ export async function getOptionMintInstructionAsync<
393
420
  TAccountEscrowAuthority extends string,
394
421
  TAccountEscrowTokenAccount extends string,
395
422
  TAccountPoolLoan extends string,
423
+ TAccountPriceUpdate extends string,
396
424
  TAccountMaker extends string,
397
425
  TAccountTokenProgram extends string,
398
426
  TAccountAssociatedTokenProgram extends string,
@@ -412,6 +440,7 @@ export async function getOptionMintInstructionAsync<
412
440
  TAccountShortMetadataAccount,
413
441
  TAccountMarketData,
414
442
  TAccountUnderlyingMint,
443
+ TAccountCollateralMint,
415
444
  TAccountOptionPool,
416
445
  TAccountEscrowLongAccount,
417
446
  TAccountPremiumVault,
@@ -425,6 +454,7 @@ export async function getOptionMintInstructionAsync<
425
454
  TAccountEscrowAuthority,
426
455
  TAccountEscrowTokenAccount,
427
456
  TAccountPoolLoan,
457
+ TAccountPriceUpdate,
428
458
  TAccountMaker,
429
459
  TAccountTokenProgram,
430
460
  TAccountAssociatedTokenProgram,
@@ -446,6 +476,7 @@ export async function getOptionMintInstructionAsync<
446
476
  TAccountShortMetadataAccount,
447
477
  TAccountMarketData,
448
478
  TAccountUnderlyingMint,
479
+ TAccountCollateralMint,
449
480
  TAccountOptionPool,
450
481
  TAccountEscrowLongAccount,
451
482
  TAccountPremiumVault,
@@ -459,6 +490,7 @@ export async function getOptionMintInstructionAsync<
459
490
  TAccountEscrowAuthority,
460
491
  TAccountEscrowTokenAccount,
461
492
  TAccountPoolLoan,
493
+ TAccountPriceUpdate,
462
494
  TAccountMaker,
463
495
  TAccountTokenProgram,
464
496
  TAccountAssociatedTokenProgram,
@@ -495,6 +527,7 @@ export async function getOptionMintInstructionAsync<
495
527
  },
496
528
  marketData: { value: input.marketData ?? null, isWritable: false },
497
529
  underlyingMint: { value: input.underlyingMint ?? null, isWritable: false },
530
+ collateralMint: { value: input.collateralMint ?? null, isWritable: false },
498
531
  optionPool: { value: input.optionPool ?? null, isWritable: true },
499
532
  escrowLongAccount: {
500
533
  value: input.escrowLongAccount ?? null,
@@ -523,6 +556,7 @@ export async function getOptionMintInstructionAsync<
523
556
  isWritable: true,
524
557
  },
525
558
  poolLoan: { value: input.poolLoan ?? null, isWritable: true },
559
+ priceUpdate: { value: input.priceUpdate ?? null, isWritable: false },
526
560
  maker: { value: input.maker ?? null, isWritable: true },
527
561
  tokenProgram: { value: input.tokenProgram ?? null, isWritable: false },
528
562
  associatedTokenProgram: {
@@ -542,7 +576,7 @@ export async function getOptionMintInstructionAsync<
542
576
  >;
543
577
 
544
578
  // Original args.
545
- const args = { ...input };
579
+ const args = { ...input, collateralMint: input.collateralMintArg };
546
580
 
547
581
  // Resolve default values.
548
582
  if (!accounts.optionAccount.value) {
@@ -771,6 +805,7 @@ export async function getOptionMintInstructionAsync<
771
805
  getAccountMeta(accounts.shortMetadataAccount),
772
806
  getAccountMeta(accounts.marketData),
773
807
  getAccountMeta(accounts.underlyingMint),
808
+ getAccountMeta(accounts.collateralMint),
774
809
  getAccountMeta(accounts.optionPool),
775
810
  getAccountMeta(accounts.escrowLongAccount),
776
811
  getAccountMeta(accounts.premiumVault),
@@ -784,6 +819,7 @@ export async function getOptionMintInstructionAsync<
784
819
  getAccountMeta(accounts.escrowAuthority),
785
820
  getAccountMeta(accounts.escrowTokenAccount),
786
821
  getAccountMeta(accounts.poolLoan),
822
+ getAccountMeta(accounts.priceUpdate),
787
823
  getAccountMeta(accounts.maker),
788
824
  getAccountMeta(accounts.tokenProgram),
789
825
  getAccountMeta(accounts.associatedTokenProgram),
@@ -807,6 +843,7 @@ export async function getOptionMintInstructionAsync<
807
843
  TAccountShortMetadataAccount,
808
844
  TAccountMarketData,
809
845
  TAccountUnderlyingMint,
846
+ TAccountCollateralMint,
810
847
  TAccountOptionPool,
811
848
  TAccountEscrowLongAccount,
812
849
  TAccountPremiumVault,
@@ -820,6 +857,7 @@ export async function getOptionMintInstructionAsync<
820
857
  TAccountEscrowAuthority,
821
858
  TAccountEscrowTokenAccount,
822
859
  TAccountPoolLoan,
860
+ TAccountPriceUpdate,
823
861
  TAccountMaker,
824
862
  TAccountTokenProgram,
825
863
  TAccountAssociatedTokenProgram,
@@ -840,6 +878,7 @@ export type OptionMintInput<
840
878
  TAccountShortMetadataAccount extends string = string,
841
879
  TAccountMarketData extends string = string,
842
880
  TAccountUnderlyingMint extends string = string,
881
+ TAccountCollateralMint extends string = string,
843
882
  TAccountOptionPool extends string = string,
844
883
  TAccountEscrowLongAccount extends string = string,
845
884
  TAccountPremiumVault extends string = string,
@@ -853,6 +892,7 @@ export type OptionMintInput<
853
892
  TAccountEscrowAuthority extends string = string,
854
893
  TAccountEscrowTokenAccount extends string = string,
855
894
  TAccountPoolLoan extends string = string,
895
+ TAccountPriceUpdate extends string = string,
856
896
  TAccountMaker extends string = string,
857
897
  TAccountTokenProgram extends string = string,
858
898
  TAccountAssociatedTokenProgram extends string = string,
@@ -884,8 +924,14 @@ export type OptionMintInput<
884
924
  shortMetadataAccount: Address<TAccountShortMetadataAccount>;
885
925
  /** Market data account - provides baseline historical volatility for initial IV */
886
926
  marketData: Address<TAccountMarketData>;
887
- /** Underlying asset mint (e.g., WSOL) - required for collateral and pool initialization */
927
+ /** Underlying asset mint (e.g., WSOL) - required for pricing and pool initialization */
888
928
  underlyingMint: Address<TAccountUnderlyingMint>;
929
+ /**
930
+ * Collateral mint (e.g., USDC, BTC, SOL) - Writer's choice for backing the position
931
+ * Can differ from underlying_mint - enables multi-collateral settlement
932
+ * OMLP vault routing is based on this mint
933
+ */
934
+ collateralMint: Address<TAccountCollateralMint>;
889
935
  /** Option pool - aggregated liquidity pool for this option */
890
936
  optionPool: Address<TAccountOptionPool>;
891
937
  /** Pool's escrow for holding LONG tokens (for buyers to purchase) */
@@ -912,6 +958,11 @@ export type OptionMintInput<
912
958
  escrowTokenAccount?: Address<TAccountEscrowTokenAccount>;
913
959
  /** Pool loan account (optional - only required if borrowing) */
914
960
  poolLoan?: Address<TAccountPoolLoan>;
961
+ /**
962
+ * Pyth price update account for collateral calculation
963
+ * Required to convert USD collateral requirement to token units
964
+ */
965
+ priceUpdate: Address<TAccountPriceUpdate>;
915
966
  maker: TransactionSigner<TAccountMaker>;
916
967
  tokenProgram?: Address<TAccountTokenProgram>;
917
968
  associatedTokenProgram?: Address<TAccountAssociatedTokenProgram>;
@@ -924,6 +975,7 @@ export type OptionMintInput<
924
975
  quantity: OptionMintInstructionDataArgs["quantity"];
925
976
  underlyingAsset: OptionMintInstructionDataArgs["underlyingAsset"];
926
977
  underlyingSymbol: OptionMintInstructionDataArgs["underlyingSymbol"];
978
+ collateralMintArg: OptionMintInstructionDataArgs["collateralMint"];
927
979
  makerCollateralAmount: OptionMintInstructionDataArgs["makerCollateralAmount"];
928
980
  borrowedAmount: OptionMintInstructionDataArgs["borrowedAmount"];
929
981
  };
@@ -939,6 +991,7 @@ export function getOptionMintInstruction<
939
991
  TAccountShortMetadataAccount extends string,
940
992
  TAccountMarketData extends string,
941
993
  TAccountUnderlyingMint extends string,
994
+ TAccountCollateralMint extends string,
942
995
  TAccountOptionPool extends string,
943
996
  TAccountEscrowLongAccount extends string,
944
997
  TAccountPremiumVault extends string,
@@ -952,6 +1005,7 @@ export function getOptionMintInstruction<
952
1005
  TAccountEscrowAuthority extends string,
953
1006
  TAccountEscrowTokenAccount extends string,
954
1007
  TAccountPoolLoan extends string,
1008
+ TAccountPriceUpdate extends string,
955
1009
  TAccountMaker extends string,
956
1010
  TAccountTokenProgram extends string,
957
1011
  TAccountAssociatedTokenProgram extends string,
@@ -971,6 +1025,7 @@ export function getOptionMintInstruction<
971
1025
  TAccountShortMetadataAccount,
972
1026
  TAccountMarketData,
973
1027
  TAccountUnderlyingMint,
1028
+ TAccountCollateralMint,
974
1029
  TAccountOptionPool,
975
1030
  TAccountEscrowLongAccount,
976
1031
  TAccountPremiumVault,
@@ -984,6 +1039,7 @@ export function getOptionMintInstruction<
984
1039
  TAccountEscrowAuthority,
985
1040
  TAccountEscrowTokenAccount,
986
1041
  TAccountPoolLoan,
1042
+ TAccountPriceUpdate,
987
1043
  TAccountMaker,
988
1044
  TAccountTokenProgram,
989
1045
  TAccountAssociatedTokenProgram,
@@ -1004,6 +1060,7 @@ export function getOptionMintInstruction<
1004
1060
  TAccountShortMetadataAccount,
1005
1061
  TAccountMarketData,
1006
1062
  TAccountUnderlyingMint,
1063
+ TAccountCollateralMint,
1007
1064
  TAccountOptionPool,
1008
1065
  TAccountEscrowLongAccount,
1009
1066
  TAccountPremiumVault,
@@ -1017,6 +1074,7 @@ export function getOptionMintInstruction<
1017
1074
  TAccountEscrowAuthority,
1018
1075
  TAccountEscrowTokenAccount,
1019
1076
  TAccountPoolLoan,
1077
+ TAccountPriceUpdate,
1020
1078
  TAccountMaker,
1021
1079
  TAccountTokenProgram,
1022
1080
  TAccountAssociatedTokenProgram,
@@ -1052,6 +1110,7 @@ export function getOptionMintInstruction<
1052
1110
  },
1053
1111
  marketData: { value: input.marketData ?? null, isWritable: false },
1054
1112
  underlyingMint: { value: input.underlyingMint ?? null, isWritable: false },
1113
+ collateralMint: { value: input.collateralMint ?? null, isWritable: false },
1055
1114
  optionPool: { value: input.optionPool ?? null, isWritable: true },
1056
1115
  escrowLongAccount: {
1057
1116
  value: input.escrowLongAccount ?? null,
@@ -1080,6 +1139,7 @@ export function getOptionMintInstruction<
1080
1139
  isWritable: true,
1081
1140
  },
1082
1141
  poolLoan: { value: input.poolLoan ?? null, isWritable: true },
1142
+ priceUpdate: { value: input.priceUpdate ?? null, isWritable: false },
1083
1143
  maker: { value: input.maker ?? null, isWritable: true },
1084
1144
  tokenProgram: { value: input.tokenProgram ?? null, isWritable: false },
1085
1145
  associatedTokenProgram: {
@@ -1099,7 +1159,7 @@ export function getOptionMintInstruction<
1099
1159
  >;
1100
1160
 
1101
1161
  // Original args.
1102
- const args = { ...input };
1162
+ const args = { ...input, collateralMint: input.collateralMintArg };
1103
1163
 
1104
1164
  // Resolve default values.
1105
1165
  if (!accounts.tokenProgram.value) {
@@ -1136,6 +1196,7 @@ export function getOptionMintInstruction<
1136
1196
  getAccountMeta(accounts.shortMetadataAccount),
1137
1197
  getAccountMeta(accounts.marketData),
1138
1198
  getAccountMeta(accounts.underlyingMint),
1199
+ getAccountMeta(accounts.collateralMint),
1139
1200
  getAccountMeta(accounts.optionPool),
1140
1201
  getAccountMeta(accounts.escrowLongAccount),
1141
1202
  getAccountMeta(accounts.premiumVault),
@@ -1149,6 +1210,7 @@ export function getOptionMintInstruction<
1149
1210
  getAccountMeta(accounts.escrowAuthority),
1150
1211
  getAccountMeta(accounts.escrowTokenAccount),
1151
1212
  getAccountMeta(accounts.poolLoan),
1213
+ getAccountMeta(accounts.priceUpdate),
1152
1214
  getAccountMeta(accounts.maker),
1153
1215
  getAccountMeta(accounts.tokenProgram),
1154
1216
  getAccountMeta(accounts.associatedTokenProgram),
@@ -1172,6 +1234,7 @@ export function getOptionMintInstruction<
1172
1234
  TAccountShortMetadataAccount,
1173
1235
  TAccountMarketData,
1174
1236
  TAccountUnderlyingMint,
1237
+ TAccountCollateralMint,
1175
1238
  TAccountOptionPool,
1176
1239
  TAccountEscrowLongAccount,
1177
1240
  TAccountPremiumVault,
@@ -1185,6 +1248,7 @@ export function getOptionMintInstruction<
1185
1248
  TAccountEscrowAuthority,
1186
1249
  TAccountEscrowTokenAccount,
1187
1250
  TAccountPoolLoan,
1251
+ TAccountPriceUpdate,
1188
1252
  TAccountMaker,
1189
1253
  TAccountTokenProgram,
1190
1254
  TAccountAssociatedTokenProgram,
@@ -1224,40 +1288,51 @@ export type ParsedOptionMintInstruction<
1224
1288
  shortMetadataAccount: TAccountMetas[7];
1225
1289
  /** Market data account - provides baseline historical volatility for initial IV */
1226
1290
  marketData: TAccountMetas[8];
1227
- /** Underlying asset mint (e.g., WSOL) - required for collateral and pool initialization */
1291
+ /** Underlying asset mint (e.g., WSOL) - required for pricing and pool initialization */
1228
1292
  underlyingMint: TAccountMetas[9];
1293
+ /**
1294
+ * Collateral mint (e.g., USDC, BTC, SOL) - Writer's choice for backing the position
1295
+ * Can differ from underlying_mint - enables multi-collateral settlement
1296
+ * OMLP vault routing is based on this mint
1297
+ */
1298
+ collateralMint: TAccountMetas[10];
1229
1299
  /** Option pool - aggregated liquidity pool for this option */
1230
- optionPool: TAccountMetas[10];
1300
+ optionPool: TAccountMetas[11];
1231
1301
  /** Pool's escrow for holding LONG tokens (for buyers to purchase) */
1232
- escrowLongAccount: TAccountMetas[11];
1302
+ escrowLongAccount: TAccountMetas[12];
1233
1303
  /** Pool's vault for collecting premiums (in underlying asset) */
1234
- premiumVault: TAccountMetas[12];
1304
+ premiumVault: TAccountMetas[13];
1235
1305
  /** Collateral pool for this option */
1236
- collateralPool: TAccountMetas[13];
1306
+ collateralPool: TAccountMetas[14];
1237
1307
  /** Collateral vault (ATA holding collateral) */
1238
- collateralVault: TAccountMetas[14];
1308
+ collateralVault: TAccountMetas[15];
1239
1309
  /** Maker's collateral account (source of maker's own collateral) */
1240
- makerCollateralAccount: TAccountMetas[15];
1310
+ makerCollateralAccount: TAccountMetas[16];
1241
1311
  /** Writer's unified position account (single source of truth) */
1242
- writerPosition: TAccountMetas[16];
1312
+ writerPosition: TAccountMetas[17];
1243
1313
  /** OMLP vault (optional - only required if borrowing) */
1244
- vault?: TAccountMetas[17] | undefined;
1314
+ vault?: TAccountMetas[18] | undefined;
1245
1315
  /** Vault's token account (optional - only required if borrowing) */
1246
- vaultTokenAccount?: TAccountMetas[18] | undefined;
1316
+ vaultTokenAccount?: TAccountMetas[19] | undefined;
1247
1317
  /** Escrow state PDA (optional - only required if borrowing) */
1248
- escrowState?: TAccountMetas[19] | undefined;
1318
+ escrowState?: TAccountMetas[20] | undefined;
1249
1319
  /** Escrow authority PDA (optional - only required if borrowing) */
1250
- escrowAuthority?: TAccountMetas[20] | undefined;
1320
+ escrowAuthority?: TAccountMetas[21] | undefined;
1251
1321
  /** Escrow token account (optional - only required if borrowing) */
1252
- escrowTokenAccount?: TAccountMetas[21] | undefined;
1322
+ escrowTokenAccount?: TAccountMetas[22] | undefined;
1253
1323
  /** Pool loan account (optional - only required if borrowing) */
1254
- poolLoan?: TAccountMetas[22] | undefined;
1255
- maker: TAccountMetas[23];
1256
- tokenProgram: TAccountMetas[24];
1257
- associatedTokenProgram: TAccountMetas[25];
1258
- tokenMetadataProgram: TAccountMetas[26];
1259
- systemProgram: TAccountMetas[27];
1260
- rent: TAccountMetas[28];
1324
+ poolLoan?: TAccountMetas[23] | undefined;
1325
+ /**
1326
+ * Pyth price update account for collateral calculation
1327
+ * Required to convert USD collateral requirement to token units
1328
+ */
1329
+ priceUpdate: TAccountMetas[24];
1330
+ maker: TAccountMetas[25];
1331
+ tokenProgram: TAccountMetas[26];
1332
+ associatedTokenProgram: TAccountMetas[27];
1333
+ tokenMetadataProgram: TAccountMetas[28];
1334
+ systemProgram: TAccountMetas[29];
1335
+ rent: TAccountMetas[30];
1261
1336
  };
1262
1337
  data: OptionMintInstructionData;
1263
1338
  };
@@ -1270,7 +1345,7 @@ export function parseOptionMintInstruction<
1270
1345
  InstructionWithAccounts<TAccountMetas> &
1271
1346
  InstructionWithData<ReadonlyUint8Array>,
1272
1347
  ): ParsedOptionMintInstruction<TProgram, TAccountMetas> {
1273
- if (instruction.accounts.length < 29) {
1348
+ if (instruction.accounts.length < 31) {
1274
1349
  // TODO: Coded error.
1275
1350
  throw new Error("Not enough accounts");
1276
1351
  }
@@ -1299,6 +1374,7 @@ export function parseOptionMintInstruction<
1299
1374
  shortMetadataAccount: getNextAccount(),
1300
1375
  marketData: getNextAccount(),
1301
1376
  underlyingMint: getNextAccount(),
1377
+ collateralMint: getNextAccount(),
1302
1378
  optionPool: getNextAccount(),
1303
1379
  escrowLongAccount: getNextAccount(),
1304
1380
  premiumVault: getNextAccount(),
@@ -1312,6 +1388,7 @@ export function parseOptionMintInstruction<
1312
1388
  escrowAuthority: getNextOptionalAccount(),
1313
1389
  escrowTokenAccount: getNextOptionalAccount(),
1314
1390
  poolLoan: getNextOptionalAccount(),
1391
+ priceUpdate: getNextAccount(),
1315
1392
  maker: getNextAccount(),
1316
1393
  tokenProgram: getNextAccount(),
1317
1394
  associatedTokenProgram: getNextAccount(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicentral/sos-sdk",
3
- "version": "0.4.0-alpha.3",
3
+ "version": "0.5.0-alpha.2",
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/shared/amounts.ts CHANGED
@@ -24,9 +24,30 @@ export function assertNonNegativeAmount(value: bigint | number, label: string):
24
24
  }
25
25
  }
26
26
 
27
+ /**
28
+ * Calculate required collateral for option position in token base units
29
+ * Matches on-chain formula: ((qty / 1_000_000) * 100 * strike) / spot * 10^decimals
30
+ *
31
+ * @param quantity - Option quantity in base units (1 contract = 1_000_000)
32
+ * @param strikePrice - Strike price in USD
33
+ * @param spotPrice - Current spot price of underlying in USD (from oracle)
34
+ * @param tokenDecimals - Number of decimals for the underlying token (e.g., 9 for SOL)
35
+ * @returns Required collateral in token base units
36
+ */
27
37
  export function calculateRequiredCollateral(
28
38
  quantity: bigint | number,
29
- strikePrice: number
39
+ strikePrice: number,
40
+ spotPrice: number,
41
+ tokenDecimals: number
30
42
  ): number {
31
- return Number(quantity) * 100 * strikePrice;
43
+ // Convert base units to contract count
44
+ const contracts = Number(quantity) / 1_000_000;
45
+ const contractSize = 100; // 1 contract = 100 units of underlying
46
+
47
+ // USD value needed for collateral
48
+ const usdRequired = contracts * contractSize * strikePrice;
49
+
50
+ // Convert USD to token base units
51
+ const baseUnits = 10 ** tokenDecimals;
52
+ return (usdRequired / spotPrice) * baseUnits;
32
53
  }
package/short/builders.ts CHANGED
@@ -38,11 +38,22 @@ export interface BuildOptionMintParams {
38
38
  quantity: bigint | number;
39
39
  underlyingAsset: AddressLike;
40
40
  underlyingSymbol: string;
41
+ /**
42
+ * Collateral mint (e.g., USDC, BTC, SOL) - Writer's choice for backing the position.
43
+ * Can differ from underlying asset - enables multi-collateral settlement.
44
+ * OMLP vault routing is based on this mint. Defaults to underlyingMint if not provided.
45
+ */
46
+ collateralMint?: AddressLike;
41
47
  makerCollateralAmount: bigint | number;
42
48
  borrowedAmount: bigint | number;
43
49
  maker: AddressLike;
44
50
  makerCollateralAccount: AddressLike;
45
51
  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;
46
57
  longMetadataAccount?: AddressLike;
47
58
  shortMetadataAccount?: AddressLike;
48
59
  optionAccount?: AddressLike;
@@ -162,6 +173,7 @@ export async function buildOptionMintInstruction(
162
173
  shortMetadataAccount: toAddress(shortMetadata!),
163
174
  marketData: params.marketData ? toAddress(params.marketData) : undefined,
164
175
  underlyingMint: toAddress(params.underlyingMint),
176
+ collateralMint: toAddress(params.collateralMint ?? params.underlyingMint),
165
177
  optionPool: params.optionPool ? toAddress(params.optionPool) : undefined,
166
178
  escrowLongAccount: params.escrowLongAccount
167
179
  ? toAddress(params.escrowLongAccount)
@@ -181,6 +193,7 @@ export async function buildOptionMintInstruction(
181
193
  ? toAddress(params.escrowTokenAccount)
182
194
  : undefined,
183
195
  poolLoan: params.poolLoan ? toAddress(params.poolLoan) : undefined,
196
+ priceUpdate: toAddress(params.priceUpdate),
184
197
  maker: toAddress(params.maker) as any,
185
198
  optionType: params.optionType,
186
199
  strikePrice: params.strikePrice,
@@ -188,6 +201,7 @@ export async function buildOptionMintInstruction(
188
201
  quantity: params.quantity,
189
202
  underlyingAsset: toAddress(params.underlyingAsset),
190
203
  underlyingSymbol: params.underlyingSymbol,
204
+ collateralMintArg: toAddress(params.collateralMint ?? params.underlyingMint),
191
205
  makerCollateralAmount: params.makerCollateralAmount,
192
206
  borrowedAmount: params.borrowedAmount,
193
207
  });
@@ -210,11 +224,25 @@ export interface BuildOptionMintTransactionWithDerivationParams {
210
224
  quantity: bigint | number;
211
225
  underlyingMint: AddressLike;
212
226
  underlyingSymbol: string;
227
+ /**
228
+ * Collateral mint (e.g., USDC, BTC, SOL) - Writer's choice for backing the position.
229
+ * Can differ from underlying asset - enables multi-collateral settlement.
230
+ * OMLP vault routing is based on this mint. Defaults to underlyingMint if not provided.
231
+ */
232
+ collateralMint?: AddressLike;
213
233
  makerCollateralAmount: bigint | number;
214
234
  borrowedAmount: bigint | number;
215
235
  maker: AddressLike;
216
- /** Optional. When omitted, the SDK derives the maker's collateral ATA for underlyingMint. */
236
+ /**
237
+ * Optional. When omitted, the SDK derives the maker's collateral ATA for collateralMint
238
+ * (or underlyingMint if collateralMint is not provided).
239
+ */
217
240
  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;
218
246
  rpc: KitRpc;
219
247
  programId?: AddressLike;
220
248
  vault?: AddressLike;
@@ -258,18 +286,20 @@ export async function buildOptionMintTransactionWithDerivation(
258
286
  });
259
287
 
260
288
  const underlyingMint = resolved.underlyingMint ?? params.underlyingMint;
289
+ const collateralMint = params.collateralMint ?? underlyingMint;
261
290
  const [makerLongAccount, makerShortAccount] = await Promise.all([
262
291
  deriveAssociatedTokenAddress(params.maker, resolved.longMint),
263
292
  deriveAssociatedTokenAddress(params.maker, resolved.shortMint),
264
293
  ]);
265
294
  const makerCollateralAccount = params.makerCollateralAccount
266
295
  ? toAddress(params.makerCollateralAccount)
267
- : await deriveAssociatedTokenAddress(params.maker, underlyingMint);
296
+ : await deriveAssociatedTokenAddress(params.maker, collateralMint);
268
297
 
269
298
  const tx = await buildOptionMintTransaction({
270
299
  ...params,
271
300
  underlyingAsset: params.underlyingAsset,
272
301
  underlyingMint,
302
+ collateralMint,
273
303
  makerCollateralAccount,
274
304
  optionAccount: resolved.optionAccount,
275
305
  longMint: resolved.longMint,
@@ -296,7 +326,7 @@ export async function buildOptionMintTransactionWithDerivation(
296
326
  await getCreateAssociatedTokenIdempotentInstructionWithAddress(
297
327
  params.maker,
298
328
  params.maker,
299
- underlyingMint,
329
+ collateralMint,
300
330
  makerCollateralAccount
301
331
  );
302
332