@epicentral/sos-sdk 0.5.0-alpha.6 → 0.5.0-alpha.8
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 +8 -5
- package/client/lookup-table.ts +1 -1
- package/generated/programs/optionProgram.ts +2 -2
- package/package.json +1 -1
- package/short/builders.ts +20 -7
- package/short/preflight.ts +34 -4
package/README.md
CHANGED
|
@@ -179,7 +179,8 @@ Use **`preflightUnwindWriterUnsold`** before building the transaction to get:
|
|
|
179
179
|
- **Collateral return calculation** (proportional share, returnable amount).
|
|
180
180
|
- Collateral-vault available, wallet fallback required, and shortfall.
|
|
181
181
|
- **Top-up UX fields:** `collateralVaultShortfall`, `needsWalletTopUp`.
|
|
182
|
-
-
|
|
182
|
+
- WSOL repay metadata: `solTopUpRequired`, `topUpRequiredForRepay`, `nativeSolAvailable`.
|
|
183
|
+
- `canRepayFully`, which now reflects effective repay solvency (including native SOL top-up capacity for WSOL paths).
|
|
183
184
|
|
|
184
185
|
If there are no active pool loans for that vault, the API still works and passes empty `remaining_accounts`.
|
|
185
186
|
|
|
@@ -205,10 +206,6 @@ const preflight = await preflightUnwindWriterUnsold({
|
|
|
205
206
|
rpc,
|
|
206
207
|
});
|
|
207
208
|
|
|
208
|
-
if (!preflight.canRepayFully) {
|
|
209
|
-
throw new Error(`Unwind blocked. Shortfall: ${preflight.summary.shortfall.toString()}`);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
209
|
const tx = await buildUnwindWriterUnsoldWithLoanRepayment({
|
|
213
210
|
underlyingAsset,
|
|
214
211
|
optionType,
|
|
@@ -217,9 +214,15 @@ const tx = await buildUnwindWriterUnsoldWithLoanRepayment({
|
|
|
217
214
|
writer,
|
|
218
215
|
unwindQty,
|
|
219
216
|
rpc,
|
|
217
|
+
includeWrapForShortfall: true, // for WSOL paths, auto-wrap net top-up when needed
|
|
218
|
+
writerSigner: walletSigner, // required when wrapping is needed
|
|
220
219
|
});
|
|
221
220
|
```
|
|
222
221
|
|
|
222
|
+
Notes:
|
|
223
|
+
- For WSOL underlyings, the builder wraps only the net required amount: `max(0, walletFallbackRequired - walletFallbackAvailable)`.
|
|
224
|
+
- If repayment is still insolvent after considering vault + fallback + native SOL top-up capacity, the builder throws an actionable insolvency error.
|
|
225
|
+
|
|
223
226
|
## Usage Examples
|
|
224
227
|
|
|
225
228
|
### Buy From Pool (market order, high-level)
|
package/client/lookup-table.ts
CHANGED
|
@@ -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("
|
|
7
|
+
devnet: address("ApcccYeyDGBieh7fGospRV7v2pJ3UjmZEMKU8V7D3eBE"),
|
|
8
8
|
mainnet: null,
|
|
9
9
|
};
|
|
10
10
|
|
|
@@ -88,7 +88,7 @@ import {
|
|
|
88
88
|
} from "../instructions";
|
|
89
89
|
|
|
90
90
|
export const OPTION_PROGRAM_PROGRAM_ADDRESS =
|
|
91
|
-
"
|
|
91
|
+
"AA1nq9oeALQRYoN6WJvmFw6oRuek5X4KfTr7vb1i2dMQ" as Address<"AA1nq9oeALQRYoN6WJvmFw6oRuek5X4KfTr7vb1i2dMQ">;
|
|
92
92
|
|
|
93
93
|
export enum OptionProgramAccount {
|
|
94
94
|
CollateralPool,
|
|
@@ -679,7 +679,7 @@ export function identifyOptionProgramInstruction(
|
|
|
679
679
|
}
|
|
680
680
|
|
|
681
681
|
export type ParsedOptionProgramInstruction<
|
|
682
|
-
TProgram extends string = "
|
|
682
|
+
TProgram extends string = "AA1nq9oeALQRYoN6WJvmFw6oRuek5X4KfTr7vb1i2dMQ",
|
|
683
683
|
> =
|
|
684
684
|
| ({
|
|
685
685
|
instructionType: OptionProgramInstruction.AcceptAdmin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epicentral/sos-sdk",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.8",
|
|
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
|
@@ -468,6 +468,7 @@ export async function buildUnwindWriterUnsoldWithLoanRepayment(
|
|
|
468
468
|
const writerRepaymentAccount =
|
|
469
469
|
params.writerRepaymentAccount ??
|
|
470
470
|
(await deriveAssociatedTokenAddress(params.writer, underlyingMint));
|
|
471
|
+
const writerDefaultRepaymentAta = await deriveAssociatedTokenAddress(params.writer, underlyingMint);
|
|
471
472
|
|
|
472
473
|
const preflight = await preflightUnwindWriterUnsold({
|
|
473
474
|
underlyingAsset: params.underlyingAsset,
|
|
@@ -480,10 +481,22 @@ export async function buildUnwindWriterUnsoldWithLoanRepayment(
|
|
|
480
481
|
programId: params.programId,
|
|
481
482
|
underlyingMint,
|
|
482
483
|
});
|
|
484
|
+
const isWsolPath = toAddress(underlyingMint) === toAddress(NATIVE_MINT);
|
|
485
|
+
const lamportsToWrap =
|
|
486
|
+
preflight.summary.walletFallbackRequired > preflight.summary.walletFallbackAvailable
|
|
487
|
+
? preflight.summary.walletFallbackRequired - preflight.summary.walletFallbackAvailable
|
|
488
|
+
: 0n;
|
|
489
|
+
|
|
483
490
|
invariant(
|
|
484
491
|
preflight.canRepayFully,
|
|
485
|
-
`Unwind cannot fully repay loans:
|
|
492
|
+
`Unwind cannot fully repay loans: required=${preflight.summary.proportionalTotalOwed} available_now=${preflight.summary.collateralVaultAvailable + preflight.summary.walletFallbackAvailable} native_sol_available=${preflight.summary.nativeSolAvailable} remaining_shortfall=${preflight.summary.proportionalTotalOwed - (preflight.summary.collateralVaultAvailable + preflight.summary.walletFallbackAvailable + preflight.summary.nativeSolAvailable)}`
|
|
486
493
|
);
|
|
494
|
+
if (isWsolPath && lamportsToWrap > 0n && !params.includeWrapForShortfall) {
|
|
495
|
+
invariant(
|
|
496
|
+
false,
|
|
497
|
+
`Unwind requires WSOL top-up of ${lamportsToWrap} lamports. Rebuild with includeWrapForShortfall=true and writerSigner.`
|
|
498
|
+
);
|
|
499
|
+
}
|
|
487
500
|
|
|
488
501
|
const unwindTx = await buildUnwindWriterUnsoldTransactionWithDerivation({
|
|
489
502
|
underlyingAsset: params.underlyingAsset,
|
|
@@ -501,11 +514,11 @@ export async function buildUnwindWriterUnsoldWithLoanRepayment(
|
|
|
501
514
|
remainingAccounts,
|
|
502
515
|
});
|
|
503
516
|
|
|
504
|
-
if (
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
517
|
+
if (params.includeWrapForShortfall && isWsolPath && lamportsToWrap > 0n) {
|
|
518
|
+
invariant(
|
|
519
|
+
toAddress(writerRepaymentAccount) === toAddress(writerDefaultRepaymentAta),
|
|
520
|
+
"WSOL auto-wrap requires writerRepaymentAccount to be the writer WSOL ATA."
|
|
521
|
+
);
|
|
509
522
|
invariant(
|
|
510
523
|
!!params.writerSigner,
|
|
511
524
|
"writerSigner is required when includeWrapForShortfall=true for WSOL shortfall top-up."
|
|
@@ -513,7 +526,7 @@ export async function buildUnwindWriterUnsoldWithLoanRepayment(
|
|
|
513
526
|
const wrapInstructions = await getWrapSOLInstructions({
|
|
514
527
|
payer: params.writerSigner,
|
|
515
528
|
owner: params.writer,
|
|
516
|
-
lamports:
|
|
529
|
+
lamports: lamportsToWrap,
|
|
517
530
|
});
|
|
518
531
|
return {
|
|
519
532
|
instructions: [...wrapInstructions, ...unwindTx.instructions],
|
package/short/preflight.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { fetchPoolLoansByMaker } from "../accounts/list";
|
|
|
6
6
|
import { deriveAssociatedTokenAddress, deriveVaultPda, deriveWriterPositionPda } from "../accounts/pdas";
|
|
7
7
|
import { resolveOptionAccounts } from "../accounts/resolve-option";
|
|
8
8
|
import { invariant } from "../shared/errors";
|
|
9
|
+
import { NATIVE_MINT } from "../wsol/instructions";
|
|
9
10
|
|
|
10
11
|
const TOKEN_ACCOUNT_AMOUNT_OFFSET = 64;
|
|
11
12
|
const BPS_DENOMINATOR = 10_000n;
|
|
@@ -78,6 +79,10 @@ export interface UnwindPreflightSummary {
|
|
|
78
79
|
/** For top-up UX: explicit shortfall fields */
|
|
79
80
|
collateralVaultShortfall: bigint;
|
|
80
81
|
needsWalletTopUp: boolean;
|
|
82
|
+
/** WSOL-only top-up metadata */
|
|
83
|
+
solTopUpRequired: bigint;
|
|
84
|
+
topUpRequiredForRepay: boolean;
|
|
85
|
+
nativeSolAvailable: bigint;
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
export interface UnwindPreflightResult {
|
|
@@ -111,9 +116,11 @@ export async function preflightUnwindWriterUnsold(
|
|
|
111
116
|
const underlyingMint = params.underlyingMint ?? resolved.underlyingMint;
|
|
112
117
|
const [vaultPda] = await deriveVaultPda(underlyingMint, params.programId);
|
|
113
118
|
const vaultPdaAddress = toAddress(vaultPda);
|
|
119
|
+
const writerAddress = toAddress(params.writer);
|
|
120
|
+
const writerDefaultRepaymentAta = await deriveAssociatedTokenAddress(params.writer, underlyingMint);
|
|
114
121
|
const writerRepaymentAccount =
|
|
115
122
|
params.writerRepaymentAccount ??
|
|
116
|
-
|
|
123
|
+
writerDefaultRepaymentAta;
|
|
117
124
|
const writerRepaymentAddress = toAddress(writerRepaymentAccount);
|
|
118
125
|
const [writerPositionAddress] = await deriveWriterPositionPda(
|
|
119
126
|
resolved.optionPool,
|
|
@@ -162,6 +169,9 @@ export async function preflightUnwindWriterUnsold(
|
|
|
162
169
|
shortfall: 0n,
|
|
163
170
|
collateralVaultShortfall: 0n,
|
|
164
171
|
needsWalletTopUp: false,
|
|
172
|
+
solTopUpRequired: 0n,
|
|
173
|
+
topUpRequiredForRepay: false,
|
|
174
|
+
nativeSolAvailable: 0n,
|
|
165
175
|
},
|
|
166
176
|
};
|
|
167
177
|
}
|
|
@@ -192,6 +202,9 @@ export async function preflightUnwindWriterUnsold(
|
|
|
192
202
|
shortfall: 0n,
|
|
193
203
|
collateralVaultShortfall: 0n,
|
|
194
204
|
needsWalletTopUp: false,
|
|
205
|
+
solTopUpRequired: 0n,
|
|
206
|
+
topUpRequiredForRepay: false,
|
|
207
|
+
nativeSolAvailable: 0n,
|
|
195
208
|
},
|
|
196
209
|
};
|
|
197
210
|
}
|
|
@@ -242,10 +255,15 @@ export async function preflightUnwindWriterUnsold(
|
|
|
242
255
|
{ principal: 0n, interest: 0n, fees: 0n, owed: 0n }
|
|
243
256
|
);
|
|
244
257
|
|
|
245
|
-
const
|
|
258
|
+
const isWsolRepaymentPath = toAddress(underlyingMint) === toAddress(NATIVE_MINT);
|
|
259
|
+
const canTopUpByWrapping =
|
|
260
|
+
isWsolRepaymentPath && writerRepaymentAddress === toAddress(writerDefaultRepaymentAta);
|
|
261
|
+
const [collateralVaultAvailable, walletFallbackAvailable, nativeBalanceResponse] = await Promise.all([
|
|
246
262
|
fetchTokenAmount(params.rpc, resolved.collateralVault!),
|
|
247
263
|
fetchTokenAmount(params.rpc, writerRepaymentAddress),
|
|
264
|
+
canTopUpByWrapping ? params.rpc.getBalance(writerAddress).send() : Promise.resolve({ value: 0n }),
|
|
248
265
|
]);
|
|
266
|
+
const nativeSolAvailable = nativeBalanceResponse.value;
|
|
249
267
|
|
|
250
268
|
// Calculate proportional obligations for partial unwinds
|
|
251
269
|
const writtenQty = toBigInt(writerPosition.writtenQty);
|
|
@@ -270,6 +288,12 @@ export async function preflightUnwindWriterUnsold(
|
|
|
270
288
|
proportionalTotalOwed > collateralVaultAvailable ? proportionalTotalOwed - collateralVaultAvailable : 0n;
|
|
271
289
|
const totalAvailable = collateralVaultAvailable + walletFallbackAvailable;
|
|
272
290
|
const shortfall = proportionalTotalOwed > totalAvailable ? proportionalTotalOwed - totalAvailable : 0n;
|
|
291
|
+
const solTopUpRequired =
|
|
292
|
+
walletFallbackRequired > walletFallbackAvailable ? walletFallbackRequired - walletFallbackAvailable : 0n;
|
|
293
|
+
const topUpRequiredForRepay = solTopUpRequired > 0n;
|
|
294
|
+
const effectiveTotalAvailable = totalAvailable + (canTopUpByWrapping ? nativeSolAvailable : 0n);
|
|
295
|
+
const effectiveShortfall =
|
|
296
|
+
proportionalTotalOwed > effectiveTotalAvailable ? proportionalTotalOwed - effectiveTotalAvailable : 0n;
|
|
273
297
|
|
|
274
298
|
// For top-up UX: explicit collateral vault shortfall
|
|
275
299
|
const collateralVaultShortfall = returnableCollateral > collateralVaultAvailable
|
|
@@ -279,8 +303,11 @@ export async function preflightUnwindWriterUnsold(
|
|
|
279
303
|
|
|
280
304
|
return {
|
|
281
305
|
canUnwind: true,
|
|
282
|
-
canRepayFully:
|
|
283
|
-
reason:
|
|
306
|
+
canRepayFully: effectiveShortfall === 0n,
|
|
307
|
+
reason:
|
|
308
|
+
effectiveShortfall === 0n
|
|
309
|
+
? undefined
|
|
310
|
+
: "Insufficient combined collateral vault + wallet fallback funds (including SOL top-up capacity for WSOL)",
|
|
284
311
|
writerPositionAddress: String(writerPositionAddress),
|
|
285
312
|
writerRepaymentAccount: String(writerRepaymentAddress),
|
|
286
313
|
collateralVaultAddress: String(resolved.collateralVault),
|
|
@@ -303,6 +330,9 @@ export async function preflightUnwindWriterUnsold(
|
|
|
303
330
|
shortfall,
|
|
304
331
|
collateralVaultShortfall,
|
|
305
332
|
needsWalletTopUp,
|
|
333
|
+
solTopUpRequired,
|
|
334
|
+
topUpRequiredForRepay,
|
|
335
|
+
nativeSolAvailable,
|
|
306
336
|
},
|
|
307
337
|
};
|
|
308
338
|
}
|