@epicentral/sos-sdk 0.9.1-beta → 0.10.1-beta

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
@@ -63,7 +63,8 @@ Additional modules:
63
63
  | `buildUnwindWriterUnsoldTransactionWithDerivation` | Builds unwind unsold transaction. |
64
64
  | `buildUnwindWriterUnsoldWithLoanRepayment` | **Unwind + repay pool loans in one tx.** Use when closing unsold shorts that borrowed from OMLP. |
65
65
  | `buildSyncWriterPositionTransaction` | Syncs writer position with pool accumulators. |
66
- | `buildSettleMakerCollateralTransaction` | Settles maker collateral after buyer closes (repays principal + accrued interest to OMLP from collateral vault first, then returns remainder to maker). |
66
+ | `buildSettleMakerCollateralTransaction` | Expiry Phase A: repays one active loan's principal + accrued interest to OMLP from collateral vault. Writers with multiple loans for the expired option call it once per loan; maker residual is claimed separately. |
67
+ | `getClaimMakerRemainingInstructionAsync` | Expiry Phase C generated instruction: returns remaining maker collateral after Phase B buyer payouts complete. |
67
68
  | `buildCloseOptionTransaction` | Closes option token account. |
68
69
  | `buildClaimThetaTransaction` | Claims theta (time-decay share) for writer. |
69
70
  | `buildRepayPoolLoanFromCollateralInstruction` | Repays pool loan from collateral (short/pool). |
@@ -77,8 +78,19 @@ Additional modules:
77
78
  - On-chain transfers for lender repayment and collateral return are authorized by program PDAs (`collateral_pool` / `option_pool`) where applicable.
78
79
  - `buildSettleMakerCollateralTransaction`
79
80
  - No maker transaction signer is required by this instruction format.
80
- - On-chain repayment (`collateral_vault` -> `omlp_vault`) and maker return are signed by the `collateral_pool` PDA.
81
+ - On-chain repayment (`collateral_vault` -> `omlp_vault`) is signed by the `collateral_pool` PDA.
81
82
  - Lender repayment is sourced from collateral vault funds, not maker wallet funds.
83
+ - Expiry residual maker collateral is returned later by `claim_maker_remaining` after buyer payout Phase B.
84
+
85
+ ### Expiry Settlement
86
+
87
+ Expiry settlement is lender-first and split across three instructions:
88
+
89
+ 1. `settle_maker_collateral` (Phase A) for every non-liquidated maker. Lender repayment is paid to the loan vault's ATA for the pool collateral mint, so devnet fake SOL/USDC pools and mainnet WSOL pools use the same mint-safe path. If a writer has multiple active `PoolLoan` accounts for that expired option, keepers submit one Phase A transaction per loan; the maker share is not marked Phase A settled until all are repaid.
90
+ 2. `auto_exercise_expired` / `auto_exercise_all_expired` (Phase B) for buyers, capped by `eligible_maker_pot`; options with zero buyer positions are considered buyer-settled so maker claims do not stall. The single and batch paths take the collateral/settlement mint so cash-settled payouts use the correct token decimals; batch remaining accounts must pair each position with that buyer's token account for the same mint.
91
+ 3. `claim_maker_remaining` (Phase C) for makers after `phase_b_complete`, returning residual collateral in the pool collateral mint.
92
+
93
+ New program errors exposed in the IDL: `LenderRepaymentNotComplete`, `BuyerPayoutNotComplete`, and `MakerLiquidated`.
82
94
 
83
95
  ### OMLP (Lending)
84
96
 
@@ -1,4 +1,6 @@
1
1
  import {
2
+ COLLATERAL_POOL_DISCRIMINATOR,
3
+ OPTION_POOL_DISCRIMINATOR,
2
4
  getCollateralPoolDecoder,
3
5
  getLenderPositionDecoder,
4
6
  getMarketDataAccountDecoder,
@@ -19,10 +21,74 @@ import {
19
21
  type WriterPosition,
20
22
  } from "../generated/accounts";
21
23
  import type { Address } from "@solana/kit";
24
+ import bs58 from "bs58";
22
25
  import { toAddress } from "../client/program";
23
26
  import type { AddressLike, KitRpc } from "../client/types";
24
27
 
25
- async function fetchRawAccount(
28
+ /** Anchor `CollateralPool`: discriminator + option_account (32) + collateral_mint (32), then collateral_vault. */
29
+ const COLLATERAL_POOL_COLLATERAL_VAULT_OFFSET =
30
+ COLLATERAL_POOL_DISCRIMINATOR.length + 32 + 32;
31
+
32
+ /** Sequential pubkeys before numeric fields (`option_pool` Anchor layout). */
33
+ const OPTION_POOL_UNDERLYING_MINT_OFFSET =
34
+ OPTION_POOL_DISCRIMINATOR.length + 32 + 32 + 32;
35
+ const OPTION_POOL_ESCROW_LONG_OFFSET = OPTION_POOL_UNDERLYING_MINT_OFFSET + 32;
36
+ const OPTION_POOL_PREMIUM_VAULT_OFFSET = OPTION_POOL_ESCROW_LONG_OFFSET + 32;
37
+
38
+ function discriminatorMatches(expected: Uint8Array, data: Uint8Array): boolean {
39
+ if (data.length < expected.length) return false;
40
+ for (let i = 0; i < expected.length; i++) {
41
+ if (data[i] !== expected[i]!) return false;
42
+ }
43
+ return true;
44
+ }
45
+
46
+ function collateralPoolDiscriminatorMatches(data: Uint8Array): boolean {
47
+ return discriminatorMatches(COLLATERAL_POOL_DISCRIMINATOR, data);
48
+ }
49
+
50
+ function optionPoolDiscriminatorMatches(data: Uint8Array): boolean {
51
+ return discriminatorMatches(OPTION_POOL_DISCRIMINATOR, data);
52
+ }
53
+
54
+ /**
55
+ * If full `OptionPool` decode fails, read the pubkey fields layout-traders need for resolving pool routes.
56
+ */
57
+ export function decodeOptionPoolTradePubkeysFromRawData(data: Uint8Array): {
58
+ underlyingMint: Address;
59
+ escrowLongAccount: Address;
60
+ premiumVault: Address;
61
+ } | undefined {
62
+ const end = OPTION_POOL_PREMIUM_VAULT_OFFSET + 32;
63
+ if (data.length < end) return undefined;
64
+ if (!optionPoolDiscriminatorMatches(data)) return undefined;
65
+ return {
66
+ underlyingMint: toAddress(
67
+ bs58.encode(data.subarray(OPTION_POOL_UNDERLYING_MINT_OFFSET, OPTION_POOL_UNDERLYING_MINT_OFFSET + 32)),
68
+ ),
69
+ escrowLongAccount: toAddress(
70
+ bs58.encode(data.subarray(OPTION_POOL_ESCROW_LONG_OFFSET, OPTION_POOL_ESCROW_LONG_OFFSET + 32)),
71
+ ),
72
+ premiumVault: toAddress(
73
+ bs58.encode(data.subarray(OPTION_POOL_PREMIUM_VAULT_OFFSET, OPTION_POOL_PREMIUM_VAULT_OFFSET + 32)),
74
+ ),
75
+ };
76
+ }
77
+
78
+ /**
79
+ * If full Codama decode fails (IDL / deployed account size mismatch), read `collateral_vault`
80
+ * from the fixed Anchor field order. This is sufficient for txs that only need vault + pool PDAs.
81
+ */
82
+ export function decodeCollateralVaultFromCollateralPoolRawData(
83
+ data: Uint8Array
84
+ ): Address | undefined {
85
+ const end = COLLATERAL_POOL_COLLATERAL_VAULT_OFFSET + 32;
86
+ if (data.length < end) return undefined;
87
+ if (!collateralPoolDiscriminatorMatches(data)) return undefined;
88
+ return toAddress(bs58.encode(data.subarray(COLLATERAL_POOL_COLLATERAL_VAULT_OFFSET, end)));
89
+ }
90
+
91
+ export async function fetchAccountData(
26
92
  rpc: KitRpc,
27
93
  address: AddressLike
28
94
  ): Promise<Uint8Array | null> {
@@ -32,7 +98,7 @@ async function fetchRawAccount(
32
98
  const [data] = accountInfo.data;
33
99
  const binary = atob(data);
34
100
  const bytes = new Uint8Array(binary.length);
35
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
101
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)!;
36
102
  return bytes;
37
103
  }
38
104
 
@@ -41,9 +107,13 @@ async function decodeAccount<T>(
41
107
  address: AddressLike,
42
108
  decoder: { decode: (value: Uint8Array) => T }
43
109
  ): Promise<T | null> {
44
- const data = await fetchRawAccount(rpc, address);
110
+ const data = await fetchAccountData(rpc, address);
45
111
  if (!data) return null;
46
- return decoder.decode(data);
112
+ try {
113
+ return decoder.decode(data);
114
+ } catch {
115
+ return null;
116
+ }
47
117
  }
48
118
 
49
119
  export async function fetchOptionAccount(
@@ -148,21 +218,21 @@ export async function fetchOptionAccounts(
148
218
  for (let i = 0; i < keys.length; i++) {
149
219
  const accountInfo = infos[i];
150
220
  if (!accountInfo) {
151
- result.set(keys[i], null);
221
+ result.set(keys[i]!, null);
152
222
  continue;
153
223
  }
154
224
  const [b64] = accountInfo.data;
155
225
  if (!b64) {
156
- result.set(keys[i], null);
226
+ result.set(keys[i]!, null);
157
227
  continue;
158
228
  }
159
229
  const binary = atob(b64);
160
230
  const data = new Uint8Array(binary.length);
161
- for (let j = 0; j < binary.length; j++) data[j] = binary.charCodeAt(j);
231
+ for (let j = 0; j < binary.length; j++) data[j] = binary.charCodeAt(j)!;
162
232
  try {
163
- result.set(keys[i], optionDecoder.decode(data));
233
+ result.set(keys[i]!, optionDecoder.decode(data));
164
234
  } catch {
165
- result.set(keys[i], null);
235
+ result.set(keys[i]!, null);
166
236
  }
167
237
  }
168
238
  return result;
package/accounts/list.ts CHANGED
@@ -97,14 +97,20 @@ async function fetchAndDecodeProgramAccounts<T>(
97
97
  ? (response as Array<ProgramAccountResponse>)
98
98
  : (response as { value: Array<ProgramAccountResponse> }).value;
99
99
 
100
- return rawAccounts.map(({ pubkey, account }) => {
100
+ const out: Array<ListedAccount<T>> = [];
101
+ for (const { pubkey, account } of rawAccounts) {
101
102
  const base64Data =
102
103
  Array.isArray(account.data) ? account.data[0] : account.data;
103
- return {
104
- address: pubkey,
105
- data: decoder.decode(decodeBase64Data(base64Data)),
106
- };
107
- });
104
+ try {
105
+ out.push({
106
+ address: pubkey,
107
+ data: decoder.decode(decodeBase64Data(base64Data)),
108
+ });
109
+ } catch {
110
+ /** Skip malformed / IDL-size mismatches instead of throwing from getProgramAccounts. */
111
+ }
112
+ }
113
+ return out;
108
114
  }
109
115
 
110
116
  export async function fetchWriterPositionsByWriter(
@@ -1,7 +1,12 @@
1
1
  import type { Address } from "@solana/kit";
2
2
  import { OptionType } from "../generated/types";
3
- import { toAddress } from "../client/program";
4
3
  import type { AddressLike, KitRpc } from "../client/types";
4
+ import type { CollateralPool, OptionAccount, OptionPool } from "../generated/accounts";
5
+ import {
6
+ getCollateralPoolDecoder,
7
+ getOptionAccountDecoder,
8
+ getOptionPoolDecoder,
9
+ } from "../generated/accounts";
5
10
  import {
6
11
  deriveCollateralPoolPda,
7
12
  deriveLongMintPda,
@@ -11,7 +16,11 @@ import {
11
16
  deriveOptionPoolPda,
12
17
  deriveShortMintPda,
13
18
  } from "./pdas";
14
- import { fetchCollateralPool, fetchOptionAccount, fetchOptionPool } from "./fetchers";
19
+ import {
20
+ decodeCollateralVaultFromCollateralPoolRawData,
21
+ decodeOptionPoolTradePubkeysFromRawData,
22
+ fetchAccountData,
23
+ } from "./fetchers";
15
24
 
16
25
  export interface ResolveOptionAccountsParams {
17
26
  underlyingAsset: AddressLike;
@@ -34,9 +43,9 @@ export interface ResolvedOptionAccounts {
34
43
  escrowLongAccount?: Address;
35
44
  premiumVault?: Address;
36
45
  collateralVault?: Address;
37
- optionPoolData?: Awaited<ReturnType<typeof fetchOptionPool>>;
38
- optionAccountData?: Awaited<ReturnType<typeof fetchOptionAccount>>;
39
- collateralPoolData?: Awaited<ReturnType<typeof fetchCollateralPool>>;
46
+ optionPoolData?: OptionPool;
47
+ optionAccountData?: OptionAccount;
48
+ collateralPoolData?: CollateralPool;
40
49
  }
41
50
 
42
51
  /**
@@ -76,27 +85,59 @@ export async function resolveOptionAccounts(
76
85
  };
77
86
 
78
87
  if (params.rpc) {
79
- const [optionPoolFetched, optionAccountFetched, collateralPoolFetched] =
88
+ const optionPoolDecoder = getOptionPoolDecoder();
89
+ const optionAccountDecoder = getOptionAccountDecoder();
90
+ const collateralPoolDecoder = getCollateralPoolDecoder();
91
+ const [optionPoolBytes, optionAccountBytes, collateralPoolBytes] =
80
92
  await Promise.all([
81
- fetchOptionPool(params.rpc, optionPool),
82
- fetchOptionAccount(params.rpc, optionAccount),
83
- fetchCollateralPool(params.rpc, collateralPool),
93
+ fetchAccountData(params.rpc, optionPool),
94
+ fetchAccountData(params.rpc, optionAccount),
95
+ fetchAccountData(params.rpc, collateralPool),
84
96
  ]);
85
97
 
86
- if (optionPoolFetched) {
87
- result.optionPoolData = optionPoolFetched;
88
- result.escrowLongAccount = optionPoolFetched.escrowLongAccount;
89
- result.premiumVault = optionPoolFetched.premiumVault;
90
- result.underlyingMint = optionPoolFetched.underlyingMint;
98
+ if (optionPoolBytes) {
99
+ let optionPoolDecoded: OptionPool | null = null;
100
+ try {
101
+ optionPoolDecoded = optionPoolDecoder.decode(optionPoolBytes);
102
+ } catch {
103
+ optionPoolDecoded = null;
104
+ }
105
+ if (optionPoolDecoded) {
106
+ result.optionPoolData = optionPoolDecoded;
107
+ result.escrowLongAccount = optionPoolDecoded.escrowLongAccount;
108
+ result.premiumVault = optionPoolDecoded.premiumVault;
109
+ result.underlyingMint = optionPoolDecoded.underlyingMint;
110
+ } else {
111
+ const tradePubkeys =
112
+ decodeOptionPoolTradePubkeysFromRawData(optionPoolBytes);
113
+ if (tradePubkeys) {
114
+ result.escrowLongAccount = tradePubkeys.escrowLongAccount;
115
+ result.premiumVault = tradePubkeys.premiumVault;
116
+ result.underlyingMint = tradePubkeys.underlyingMint;
117
+ }
118
+ }
91
119
  }
92
120
 
93
- if (optionAccountFetched) {
94
- result.optionAccountData = optionAccountFetched;
121
+ if (optionAccountBytes) {
122
+ try {
123
+ result.optionAccountData = optionAccountDecoder.decode(optionAccountBytes);
124
+ } catch {
125
+ /* layout drift: PDAs remain valid; Greeks-only consumers see no OptionAccount snapshot */
126
+ }
95
127
  }
96
128
 
97
- if (collateralPoolFetched) {
98
- result.collateralPoolData = collateralPoolFetched;
99
- result.collateralVault = collateralPoolFetched.collateralVault;
129
+ if (collateralPoolBytes) {
130
+ try {
131
+ const collateralPoolFetched = collateralPoolDecoder.decode(collateralPoolBytes);
132
+ result.collateralPoolData = collateralPoolFetched;
133
+ result.collateralVault = collateralPoolFetched.collateralVault;
134
+ } catch {
135
+ const vaultFallback =
136
+ decodeCollateralVaultFromCollateralPoolRawData(collateralPoolBytes);
137
+ if (vaultFallback) {
138
+ result.collateralVault = vaultFallback;
139
+ }
140
+ }
100
141
  }
101
142
  }
102
143
 
@@ -70,6 +70,13 @@ export type CollateralPool = {
70
70
  makerCount: number;
71
71
  isExercised: boolean;
72
72
  isFullySettled: boolean;
73
+ phaseAComplete: boolean;
74
+ phaseBComplete: boolean;
75
+ eligibleMakerPot: bigint;
76
+ remainingMakerPostDebtCollateral: bigint;
77
+ eligibleMakerCount: number;
78
+ makersPhaseASettled: number;
79
+ totalBuyerIntrinsicOwedSnapshot: bigint;
73
80
  createdAt: bigint;
74
81
  lastUpdated: bigint;
75
82
  bump: number;
@@ -89,6 +96,13 @@ export type CollateralPoolArgs = {
89
96
  makerCount: number;
90
97
  isExercised: boolean;
91
98
  isFullySettled: boolean;
99
+ phaseAComplete: boolean;
100
+ phaseBComplete: boolean;
101
+ eligibleMakerPot: number | bigint;
102
+ remainingMakerPostDebtCollateral: number | bigint;
103
+ eligibleMakerCount: number;
104
+ makersPhaseASettled: number;
105
+ totalBuyerIntrinsicOwedSnapshot: number | bigint;
92
106
  createdAt: number | bigint;
93
107
  lastUpdated: number | bigint;
94
108
  bump: number;
@@ -112,6 +126,13 @@ export function getCollateralPoolEncoder(): FixedSizeEncoder<CollateralPoolArgs>
112
126
  ["makerCount", getU32Encoder()],
113
127
  ["isExercised", getBooleanEncoder()],
114
128
  ["isFullySettled", getBooleanEncoder()],
129
+ ["phaseAComplete", getBooleanEncoder()],
130
+ ["phaseBComplete", getBooleanEncoder()],
131
+ ["eligibleMakerPot", getU64Encoder()],
132
+ ["remainingMakerPostDebtCollateral", getU64Encoder()],
133
+ ["eligibleMakerCount", getU32Encoder()],
134
+ ["makersPhaseASettled", getU32Encoder()],
135
+ ["totalBuyerIntrinsicOwedSnapshot", getU64Encoder()],
115
136
  ["createdAt", getI64Encoder()],
116
137
  ["lastUpdated", getI64Encoder()],
117
138
  ["bump", getU8Encoder()],
@@ -137,6 +158,13 @@ export function getCollateralPoolDecoder(): FixedSizeDecoder<CollateralPool> {
137
158
  ["makerCount", getU32Decoder()],
138
159
  ["isExercised", getBooleanDecoder()],
139
160
  ["isFullySettled", getBooleanDecoder()],
161
+ ["phaseAComplete", getBooleanDecoder()],
162
+ ["phaseBComplete", getBooleanDecoder()],
163
+ ["eligibleMakerPot", getU64Decoder()],
164
+ ["remainingMakerPostDebtCollateral", getU64Decoder()],
165
+ ["eligibleMakerCount", getU32Decoder()],
166
+ ["makersPhaseASettled", getU32Decoder()],
167
+ ["totalBuyerIntrinsicOwedSnapshot", getU64Decoder()],
140
168
  ["createdAt", getI64Decoder()],
141
169
  ["lastUpdated", getI64Decoder()],
142
170
  ["bump", getU8Decoder()],
@@ -213,5 +241,5 @@ export async function fetchAllMaybeCollateralPool(
213
241
  }
214
242
 
215
243
  export function getCollateralPoolSize(): number {
216
- return 183;
244
+ return 217;
217
245
  }
@@ -65,7 +65,9 @@ export type MakerCollateralShare = {
65
65
  premiumCollected: bigint;
66
66
  exercisePayout: bigint;
67
67
  lenderRepayment: bigint;
68
+ postDebtCollateral: bigint;
68
69
  makerReturn: bigint;
70
+ phaseASettled: boolean;
69
71
  isSettled: boolean;
70
72
  realizedPnl: bigint;
71
73
  createdAt: bigint;
@@ -84,7 +86,9 @@ export type MakerCollateralShareArgs = {
84
86
  premiumCollected: number | bigint;
85
87
  exercisePayout: number | bigint;
86
88
  lenderRepayment: number | bigint;
89
+ postDebtCollateral: number | bigint;
87
90
  makerReturn: number | bigint;
91
+ phaseASettled: boolean;
88
92
  isSettled: boolean;
89
93
  realizedPnl: number | bigint;
90
94
  createdAt: number | bigint;
@@ -107,7 +111,9 @@ export function getMakerCollateralShareEncoder(): FixedSizeEncoder<MakerCollater
107
111
  ["premiumCollected", getU64Encoder()],
108
112
  ["exercisePayout", getU64Encoder()],
109
113
  ["lenderRepayment", getU64Encoder()],
114
+ ["postDebtCollateral", getU64Encoder()],
110
115
  ["makerReturn", getU64Encoder()],
116
+ ["phaseASettled", getBooleanEncoder()],
111
117
  ["isSettled", getBooleanEncoder()],
112
118
  ["realizedPnl", getI64Encoder()],
113
119
  ["createdAt", getI64Encoder()],
@@ -135,7 +141,9 @@ export function getMakerCollateralShareDecoder(): FixedSizeDecoder<MakerCollater
135
141
  ["premiumCollected", getU64Decoder()],
136
142
  ["exercisePayout", getU64Decoder()],
137
143
  ["lenderRepayment", getU64Decoder()],
144
+ ["postDebtCollateral", getU64Decoder()],
138
145
  ["makerReturn", getU64Decoder()],
146
+ ["phaseASettled", getBooleanDecoder()],
139
147
  ["isSettled", getBooleanDecoder()],
140
148
  ["realizedPnl", getI64Decoder()],
141
149
  ["createdAt", getI64Decoder()],
@@ -225,5 +233,5 @@ export async function fetchAllMaybeMakerCollateralShare(
225
233
  }
226
234
 
227
235
  export function getMakerCollateralShareSize(): number {
228
- return 194;
236
+ return 203;
229
237
  }
@@ -154,78 +154,84 @@ export const OPTION_PROGRAM_ERROR__COLLATERAL_POOL_NOT_FOUND = 0x17b3; // 6067
154
154
  export const OPTION_PROGRAM_ERROR__NO_COLLATERAL_TO_WITHDRAW = 0x17b4; // 6068
155
155
  /** OptionNotExpired: Option has not expired yet - cannot settle */
156
156
  export const OPTION_PROGRAM_ERROR__OPTION_NOT_EXPIRED = 0x17b5; // 6069
157
+ /** LenderRepaymentNotComplete: Lender repayment phase is not complete */
158
+ export const OPTION_PROGRAM_ERROR__LENDER_REPAYMENT_NOT_COMPLETE = 0x17b6; // 6070
159
+ /** BuyerPayoutNotComplete: Buyer payout phase is not complete */
160
+ export const OPTION_PROGRAM_ERROR__BUYER_PAYOUT_NOT_COMPLETE = 0x17b7; // 6071
161
+ /** MakerLiquidated: Maker was liquidated and is excluded from expiry settlement */
162
+ export const OPTION_PROGRAM_ERROR__MAKER_LIQUIDATED = 0x17b8; // 6072
157
163
  /** SupplyLimitExceeded: Deposit would exceed vault supply limit */
158
- export const OPTION_PROGRAM_ERROR__SUPPLY_LIMIT_EXCEEDED = 0x17b6; // 6070
164
+ export const OPTION_PROGRAM_ERROR__SUPPLY_LIMIT_EXCEEDED = 0x17b9; // 6073
159
165
  /** InvalidFeeWallet: Invalid fee wallet - must match protocol constant */
160
- export const OPTION_PROGRAM_ERROR__INVALID_FEE_WALLET = 0x17b7; // 6071
166
+ export const OPTION_PROGRAM_ERROR__INVALID_FEE_WALLET = 0x17ba; // 6074
161
167
  /** InvalidProtocolFee: Invalid protocol fee rate */
162
- export const OPTION_PROGRAM_ERROR__INVALID_PROTOCOL_FEE = 0x17b8; // 6072
168
+ export const OPTION_PROGRAM_ERROR__INVALID_PROTOCOL_FEE = 0x17bb; // 6075
163
169
  /** UnderlyingAssetMismatch: Underlying asset mismatch - market data or mint does not match option */
164
- export const OPTION_PROGRAM_ERROR__UNDERLYING_ASSET_MISMATCH = 0x17b9; // 6073
170
+ export const OPTION_PROGRAM_ERROR__UNDERLYING_ASSET_MISMATCH = 0x17bc; // 6076
165
171
  /** InvalidMint: Invalid token mint - does not match expected underlying asset */
166
- export const OPTION_PROGRAM_ERROR__INVALID_MINT = 0x17ba; // 6074
172
+ export const OPTION_PROGRAM_ERROR__INVALID_MINT = 0x17bd; // 6077
167
173
  /** BatchSizeExceeded: Batch size exceeds maximum allowed (10 positions) */
168
- export const OPTION_PROGRAM_ERROR__BATCH_SIZE_EXCEEDED = 0x17bb; // 6075
174
+ export const OPTION_PROGRAM_ERROR__BATCH_SIZE_EXCEEDED = 0x17be; // 6078
169
175
  /** NoPositionsProvided: No positions provided in batch */
170
- export const OPTION_PROGRAM_ERROR__NO_POSITIONS_PROVIDED = 0x17bc; // 6076
176
+ export const OPTION_PROGRAM_ERROR__NO_POSITIONS_PROVIDED = 0x17bf; // 6079
171
177
  /** PositionOptionMismatch: Position account does not belong to this option */
172
- export const OPTION_PROGRAM_ERROR__POSITION_OPTION_MISMATCH = 0x17bd; // 6077
178
+ export const OPTION_PROGRAM_ERROR__POSITION_OPTION_MISMATCH = 0x17c0; // 6080
173
179
  /** OptionPoolMismatch: Option account does not match the option pool's option account */
174
- export const OPTION_PROGRAM_ERROR__OPTION_POOL_MISMATCH = 0x17be; // 6078
180
+ export const OPTION_PROGRAM_ERROR__OPTION_POOL_MISMATCH = 0x17c1; // 6081
175
181
  /** InvalidSeed: Invalid seed - must be exactly 32 bytes */
176
- export const OPTION_PROGRAM_ERROR__INVALID_SEED = 0x17bf; // 6079
182
+ export const OPTION_PROGRAM_ERROR__INVALID_SEED = 0x17c2; // 6082
177
183
  /** InvalidAuthority: Invalid authority - does not match escrow authority */
178
- export const OPTION_PROGRAM_ERROR__INVALID_AUTHORITY = 0x17c0; // 6080
184
+ export const OPTION_PROGRAM_ERROR__INVALID_AUTHORITY = 0x17c3; // 6083
179
185
  /** EscrowAccountRequired: Escrow accounts required when borrowed_amount > 0 */
180
- export const OPTION_PROGRAM_ERROR__ESCROW_ACCOUNT_REQUIRED = 0x17c1; // 6081
186
+ export const OPTION_PROGRAM_ERROR__ESCROW_ACCOUNT_REQUIRED = 0x17c4; // 6084
181
187
  /** InvalidEscrowMaker: Escrow state maker does not match instruction maker */
182
- export const OPTION_PROGRAM_ERROR__INVALID_ESCROW_MAKER = 0x17c2; // 6082
188
+ export const OPTION_PROGRAM_ERROR__INVALID_ESCROW_MAKER = 0x17c5; // 6085
183
189
  /** EscrowMintMismatch: Escrow collateral mint does not match collateral pool mint */
184
- export const OPTION_PROGRAM_ERROR__ESCROW_MINT_MISMATCH = 0x17c3; // 6083
190
+ export const OPTION_PROGRAM_ERROR__ESCROW_MINT_MISMATCH = 0x17c6; // 6086
185
191
  /** InsufficientEscrowBalance: Insufficient balance in escrow token account */
186
- export const OPTION_PROGRAM_ERROR__INSUFFICIENT_ESCROW_BALANCE = 0x17c4; // 6084
192
+ export const OPTION_PROGRAM_ERROR__INSUFFICIENT_ESCROW_BALANCE = 0x17c7; // 6087
187
193
  /** InvalidEscrowOwner: Escrow token account owner mismatch */
188
- export const OPTION_PROGRAM_ERROR__INVALID_ESCROW_OWNER = 0x17c5; // 6085
194
+ export const OPTION_PROGRAM_ERROR__INVALID_ESCROW_OWNER = 0x17c8; // 6088
189
195
  /** InvalidEscrowMint: Escrow token account mint mismatch */
190
- export const OPTION_PROGRAM_ERROR__INVALID_ESCROW_MINT = 0x17c6; // 6086
196
+ export const OPTION_PROGRAM_ERROR__INVALID_ESCROW_MINT = 0x17c9; // 6089
191
197
  /** AccountFrozen: Token account is frozen and cannot be burned */
192
- export const OPTION_PROGRAM_ERROR__ACCOUNT_FROZEN = 0x17c7; // 6087
198
+ export const OPTION_PROGRAM_ERROR__ACCOUNT_FROZEN = 0x17ca; // 6090
193
199
  /** InvalidAccount: Invalid account - does not match expected account */
194
- export const OPTION_PROGRAM_ERROR__INVALID_ACCOUNT = 0x17c8; // 6088
200
+ export const OPTION_PROGRAM_ERROR__INVALID_ACCOUNT = 0x17cb; // 6091
195
201
  /** UnwindRepayAccountsMissing: Unwind repayment accounts are required when active pool loans exist */
196
- export const OPTION_PROGRAM_ERROR__UNWIND_REPAY_ACCOUNTS_MISSING = 0x17c9; // 6089
202
+ export const OPTION_PROGRAM_ERROR__UNWIND_REPAY_ACCOUNTS_MISSING = 0x17cc; // 6092
197
203
  /** InsufficientCollateralVault: Collateral vault has insufficient funds for unwind collateral return */
198
- export const OPTION_PROGRAM_ERROR__INSUFFICIENT_COLLATERAL_VAULT = 0x17ca; // 6090
204
+ export const OPTION_PROGRAM_ERROR__INSUFFICIENT_COLLATERAL_VAULT = 0x17cd; // 6093
199
205
  /** InvalidVaultMint: Invalid vault mint - does not match expected collateral mint */
200
- export const OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT = 0x17cb; // 6091
206
+ export const OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT = 0x17ce; // 6094
201
207
  /** InvalidCollateralMint: Invalid collateral mint - not supported or no vault exists */
202
- export const OPTION_PROGRAM_ERROR__INVALID_COLLATERAL_MINT = 0x17cc; // 6092
208
+ export const OPTION_PROGRAM_ERROR__INVALID_COLLATERAL_MINT = 0x17cf; // 6095
203
209
  /** CollateralMismatch: Collateral mint mismatch - position uses different collateral type */
204
- export const OPTION_PROGRAM_ERROR__COLLATERAL_MISMATCH = 0x17cd; // 6093
210
+ export const OPTION_PROGRAM_ERROR__COLLATERAL_MISMATCH = 0x17d0; // 6096
205
211
  /** BuyRemainingAccountsUnsorted: buy_from_pool remaining_accounts are not sorted by (created_at asc, pubkey asc) */
206
- export const OPTION_PROGRAM_ERROR__BUY_REMAINING_ACCOUNTS_UNSORTED = 0x17ce; // 6094
212
+ export const OPTION_PROGRAM_ERROR__BUY_REMAINING_ACCOUNTS_UNSORTED = 0x17d1; // 6097
207
213
  /** CloseLongWritersIncomplete: close_long_to_pool requires a complete set of active WriterPositions: sum(sold_qty) must equal pool.total_sold_qty */
208
- export const OPTION_PROGRAM_ERROR__CLOSE_LONG_WRITERS_INCOMPLETE = 0x17cf; // 6095
214
+ export const OPTION_PROGRAM_ERROR__CLOSE_LONG_WRITERS_INCOMPLETE = 0x17d2; // 6098
209
215
  /** CloseLongNoSoldInventory: close_long_to_pool cannot run because no writer has sold inventory for this pool */
210
- export const OPTION_PROGRAM_ERROR__CLOSE_LONG_NO_SOLD_INVENTORY = 0x17d0; // 6096
216
+ export const OPTION_PROGRAM_ERROR__CLOSE_LONG_NO_SOLD_INVENTORY = 0x17d3; // 6099
211
217
  /** CloseLongDuplicateWriter: close_long_to_pool remaining_accounts contain duplicate WriterPosition entries */
212
- export const OPTION_PROGRAM_ERROR__CLOSE_LONG_DUPLICATE_WRITER = 0x17d1; // 6097
218
+ export const OPTION_PROGRAM_ERROR__CLOSE_LONG_DUPLICATE_WRITER = 0x17d4; // 6100
213
219
  /** MaintenanceBufferBreached: Writer position breaches maintenance buffer: free_collateral + claimable_theta < accrued_interest + fees + buffer */
214
- export const OPTION_PROGRAM_ERROR__MAINTENANCE_BUFFER_BREACHED = 0x17d2; // 6098
220
+ export const OPTION_PROGRAM_ERROR__MAINTENANCE_BUFFER_BREACHED = 0x17d5; // 6101
215
221
  /** LiquidationInsufficientCollateralForDebt: Liquidation cannot cover full debt (principal + interest + fees) from writer's collateral + theta; call rescue path instead */
216
- export const OPTION_PROGRAM_ERROR__LIQUIDATION_INSUFFICIENT_COLLATERAL_FOR_DEBT = 0x17d3; // 6099
222
+ export const OPTION_PROGRAM_ERROR__LIQUIDATION_INSUFFICIENT_COLLATERAL_FOR_DEBT = 0x17d6; // 6102
217
223
  /** ThetaClaimDisabled: claim_theta instruction has been removed; theta is now auto-realized on unwind or forfeited on liquidation */
218
- export const OPTION_PROGRAM_ERROR__THETA_CLAIM_DISABLED = 0x17d4; // 6100
224
+ export const OPTION_PROGRAM_ERROR__THETA_CLAIM_DISABLED = 0x17d7; // 6103
219
225
  /** PoolLoanWriterMismatch: PoolLoan.writer_position does not match the WriterPosition in this instruction */
220
- export const OPTION_PROGRAM_ERROR__POOL_LOAN_WRITER_MISMATCH = 0x17d5; // 6101
226
+ export const OPTION_PROGRAM_ERROR__POOL_LOAN_WRITER_MISMATCH = 0x17d8; // 6104
221
227
  /** MaintenanceLoansIncomplete: Maintenance debt sync remaining_accounts must contain every active PoolLoan for this writer */
222
- export const OPTION_PROGRAM_ERROR__MAINTENANCE_LOANS_INCOMPLETE = 0x17d6; // 6102
228
+ export const OPTION_PROGRAM_ERROR__MAINTENANCE_LOANS_INCOMPLETE = 0x17d9; // 6105
223
229
  /** RescueUnauthorized: Rescue liquidation is gated to the vault keeper */
224
- export const OPTION_PROGRAM_ERROR__RESCUE_UNAUTHORIZED = 0x17d7; // 6103
230
+ export const OPTION_PROGRAM_ERROR__RESCUE_UNAUTHORIZED = 0x17da; // 6106
225
231
  /** InvalidLoanRepayment: Loan repayment amount exceeds synced balances (principal/interest/fees) */
226
- export const OPTION_PROGRAM_ERROR__INVALID_LOAN_REPAYMENT = 0x17d8; // 6104
232
+ export const OPTION_PROGRAM_ERROR__INVALID_LOAN_REPAYMENT = 0x17db; // 6107
227
233
  /** RescuePreconditionsNotMet: Rescue preconditions not met: collateral_vault must be short of the remaining debt after theta forfeiture */
228
- export const OPTION_PROGRAM_ERROR__RESCUE_PRECONDITIONS_NOT_MET = 0x17d9; // 6105
234
+ export const OPTION_PROGRAM_ERROR__RESCUE_PRECONDITIONS_NOT_MET = 0x17dc; // 6108
229
235
 
230
236
  export type OptionProgramError =
231
237
  | typeof OPTION_PROGRAM_ERROR__ACCOUNT_FROZEN
@@ -233,6 +239,7 @@ export type OptionProgramError =
233
239
  | typeof OPTION_PROGRAM_ERROR__ARITHMETIC_OVERFLOW
234
240
  | typeof OPTION_PROGRAM_ERROR__ARITHMETIC_UNDERFLOW
235
241
  | typeof OPTION_PROGRAM_ERROR__BATCH_SIZE_EXCEEDED
242
+ | typeof OPTION_PROGRAM_ERROR__BUYER_PAYOUT_NOT_COMPLETE
236
243
  | typeof OPTION_PROGRAM_ERROR__BUY_REMAINING_ACCOUNTS_UNSORTED
237
244
  | typeof OPTION_PROGRAM_ERROR__CLOSE_LONG_DUPLICATE_WRITER
238
245
  | typeof OPTION_PROGRAM_ERROR__CLOSE_LONG_NO_SOLD_INVENTORY
@@ -289,10 +296,12 @@ export type OptionProgramError =
289
296
  | typeof OPTION_PROGRAM_ERROR__INVALID_UNDERLYING_PRICE
290
297
  | typeof OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT
291
298
  | typeof OPTION_PROGRAM_ERROR__INVALID_VOLATILITY
299
+ | typeof OPTION_PROGRAM_ERROR__LENDER_REPAYMENT_NOT_COMPLETE
292
300
  | typeof OPTION_PROGRAM_ERROR__LIQUIDATION_INSUFFICIENT_COLLATERAL_FOR_DEBT
293
301
  | typeof OPTION_PROGRAM_ERROR__LOW_ORACLE_PRICE_CONFIDENCE
294
302
  | typeof OPTION_PROGRAM_ERROR__MAINTENANCE_BUFFER_BREACHED
295
303
  | typeof OPTION_PROGRAM_ERROR__MAINTENANCE_LOANS_INCOMPLETE
304
+ | typeof OPTION_PROGRAM_ERROR__MAKER_LIQUIDATED
296
305
  | typeof OPTION_PROGRAM_ERROR__MARKET_CLOSED
297
306
  | typeof OPTION_PROGRAM_ERROR__MAXIMUM_POSITION_SIZE_EXCEEDED
298
307
  | typeof OPTION_PROGRAM_ERROR__MAX_POSITIONS_REACHED
@@ -343,6 +352,7 @@ if (process.env.NODE_ENV !== "production") {
343
352
  [OPTION_PROGRAM_ERROR__ARITHMETIC_OVERFLOW]: `Arithmetic overflow occurred`,
344
353
  [OPTION_PROGRAM_ERROR__ARITHMETIC_UNDERFLOW]: `Arithmetic underflow occurred`,
345
354
  [OPTION_PROGRAM_ERROR__BATCH_SIZE_EXCEEDED]: `Batch size exceeds maximum allowed (10 positions)`,
355
+ [OPTION_PROGRAM_ERROR__BUYER_PAYOUT_NOT_COMPLETE]: `Buyer payout phase is not complete`,
346
356
  [OPTION_PROGRAM_ERROR__BUY_REMAINING_ACCOUNTS_UNSORTED]: `buy_from_pool remaining_accounts are not sorted by (created_at asc, pubkey asc)`,
347
357
  [OPTION_PROGRAM_ERROR__CLOSE_LONG_DUPLICATE_WRITER]: `close_long_to_pool remaining_accounts contain duplicate WriterPosition entries`,
348
358
  [OPTION_PROGRAM_ERROR__CLOSE_LONG_NO_SOLD_INVENTORY]: `close_long_to_pool cannot run because no writer has sold inventory for this pool`,
@@ -399,10 +409,12 @@ if (process.env.NODE_ENV !== "production") {
399
409
  [OPTION_PROGRAM_ERROR__INVALID_UNDERLYING_PRICE]: `Underlying price is invalid`,
400
410
  [OPTION_PROGRAM_ERROR__INVALID_VAULT_MINT]: `Invalid vault mint - does not match expected collateral mint`,
401
411
  [OPTION_PROGRAM_ERROR__INVALID_VOLATILITY]: `Volatility must be greater than zero`,
412
+ [OPTION_PROGRAM_ERROR__LENDER_REPAYMENT_NOT_COMPLETE]: `Lender repayment phase is not complete`,
402
413
  [OPTION_PROGRAM_ERROR__LIQUIDATION_INSUFFICIENT_COLLATERAL_FOR_DEBT]: `Liquidation cannot cover full debt (principal + interest + fees) from writer's collateral + theta; call rescue path instead`,
403
414
  [OPTION_PROGRAM_ERROR__LOW_ORACLE_PRICE_CONFIDENCE]: `Oracle price confidence is too low`,
404
415
  [OPTION_PROGRAM_ERROR__MAINTENANCE_BUFFER_BREACHED]: `Writer position breaches maintenance buffer: free_collateral + claimable_theta < accrued_interest + fees + buffer`,
405
416
  [OPTION_PROGRAM_ERROR__MAINTENANCE_LOANS_INCOMPLETE]: `Maintenance debt sync remaining_accounts must contain every active PoolLoan for this writer`,
417
+ [OPTION_PROGRAM_ERROR__MAKER_LIQUIDATED]: `Maker was liquidated and is excluded from expiry settlement`,
406
418
  [OPTION_PROGRAM_ERROR__MARKET_CLOSED]: `Market is closed`,
407
419
  [OPTION_PROGRAM_ERROR__MAXIMUM_POSITION_SIZE_EXCEEDED]: `Maximum position size exceeded`,
408
420
  [OPTION_PROGRAM_ERROR__MAX_POSITIONS_REACHED]: `Maximum positions limit reached`,