@epicentral/sos-sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +239 -0
- package/accounts/fetchers.ts +140 -0
- package/accounts/list.ts +152 -0
- package/accounts/pdas.ts +308 -0
- package/client/lookup-table.ts +32 -0
- package/client/program.ts +13 -0
- package/client/types.ts +8 -0
- package/generated/accounts/collateralPool.ts +217 -0
- package/generated/accounts/config.ts +156 -0
- package/generated/accounts/dualSourceContract.ts +235 -0
- package/generated/accounts/escrowState.ts +183 -0
- package/generated/accounts/index.ts +24 -0
- package/generated/accounts/lenderPosition.ts +211 -0
- package/generated/accounts/liquidityRouter.ts +223 -0
- package/generated/accounts/makerCollateralShare.ts +229 -0
- package/generated/accounts/makerPoolShare.ts +203 -0
- package/generated/accounts/marketDataAccount.ts +176 -0
- package/generated/accounts/optionAccount.ts +247 -0
- package/generated/accounts/optionPool.ts +253 -0
- package/generated/accounts/poolLoan.ts +220 -0
- package/generated/accounts/positionAccount.ts +187 -0
- package/generated/accounts/priceUpdateV2.ts +163 -0
- package/generated/accounts/vault.ts +304 -0
- package/generated/accounts/writerPosition.ts +297 -0
- package/generated/errors/index.ts +9 -0
- package/generated/errors/optionProgram.ts +392 -0
- package/generated/index.ts +13 -0
- package/generated/instructions/acceptAdmin.ts +230 -0
- package/generated/instructions/autoExerciseAllExpired.ts +523 -0
- package/generated/instructions/autoExerciseExpired.ts +623 -0
- package/generated/instructions/borrowFromPool.ts +554 -0
- package/generated/instructions/buyFromPool.ts +684 -0
- package/generated/instructions/claimPremium.ts +377 -0
- package/generated/instructions/closeLongToPool.ts +716 -0
- package/generated/instructions/closeOption.ts +235 -0
- package/generated/instructions/createEscrowV2.ts +518 -0
- package/generated/instructions/createLiquidityRouter.ts +361 -0
- package/generated/instructions/depositCollateral.ts +624 -0
- package/generated/instructions/depositToPool.ts +497 -0
- package/generated/instructions/depositToPosition.ts +429 -0
- package/generated/instructions/index.ts +45 -0
- package/generated/instructions/initCollateralPool.ts +513 -0
- package/generated/instructions/initConfig.ts +279 -0
- package/generated/instructions/initOptionPool.ts +587 -0
- package/generated/instructions/initializeMarketData.ts +359 -0
- package/generated/instructions/liquidateWriterPosition.ts +592 -0
- package/generated/instructions/omlpCreateVault.ts +547 -0
- package/generated/instructions/omlpTakeOfferWithFailover.ts +606 -0
- package/generated/instructions/omlpUpdateMaxLeverage.ts +304 -0
- package/generated/instructions/omlpUpdateProtocolFee.ts +304 -0
- package/generated/instructions/omlpUpdateSupplyLimit.ts +304 -0
- package/generated/instructions/optionExercise.ts +540 -0
- package/generated/instructions/optionMint.ts +1349 -0
- package/generated/instructions/optionValidate.ts +255 -0
- package/generated/instructions/repayPoolLoan.ts +499 -0
- package/generated/instructions/repayPoolLoanFromCollateral.ts +514 -0
- package/generated/instructions/settleMakerCollateral.ts +472 -0
- package/generated/instructions/syncWriterPosition.ts +206 -0
- package/generated/instructions/transferAdmin.ts +245 -0
- package/generated/instructions/unwindWriterUnsold.ts +668 -0
- package/generated/instructions/updateImpliedVolatility.ts +226 -0
- package/generated/instructions/updateMarketData.ts +315 -0
- package/generated/instructions/withdrawFromPool.ts +429 -0
- package/generated/instructions/withdrawFromPosition.ts +405 -0
- package/generated/instructions/writeToPool.ts +594 -0
- package/generated/programs/index.ts +9 -0
- package/generated/programs/optionProgram.ts +832 -0
- package/generated/shared/index.ts +164 -0
- package/generated/types/borrowedFromSAP1.ts +75 -0
- package/generated/types/borrowedFromSAP2.ts +83 -0
- package/generated/types/failoverTriggered.ts +85 -0
- package/generated/types/impliedVolatilityUpdated.ts +73 -0
- package/generated/types/index.ts +32 -0
- package/generated/types/liquidationExecuted.ts +73 -0
- package/generated/types/liquidityMetrics.ts +69 -0
- package/generated/types/liquidityRouterCreated.ts +79 -0
- package/generated/types/marketDataInitialized.ts +61 -0
- package/generated/types/marketDataUpdated.ts +69 -0
- package/generated/types/optionClosed.ts +56 -0
- package/generated/types/optionExercised.ts +62 -0
- package/generated/types/optionExpired.ts +49 -0
- package/generated/types/optionMinted.ts +78 -0
- package/generated/types/optionType.ts +38 -0
- package/generated/types/optionValidated.ts +82 -0
- package/generated/types/poolLoanCreated.ts +74 -0
- package/generated/types/poolLoanRepaid.ts +74 -0
- package/generated/types/positionDeposited.ts +73 -0
- package/generated/types/positionWithdrawn.ts +81 -0
- package/generated/types/priceFeedMessage.ts +117 -0
- package/generated/types/protocolFeeUpdated.ts +69 -0
- package/generated/types/sap2Provider.ts +38 -0
- package/generated/types/vaultCreated.ts +60 -0
- package/generated/types/verificationLevel.ts +95 -0
- package/index.ts +25 -0
- package/long/builders.ts +126 -0
- package/long/exercise.ts +49 -0
- package/long/quotes.ts +48 -0
- package/omlp/builders.ts +74 -0
- package/omlp/service.ts +94 -0
- package/package.json +22 -0
- package/shared/amounts.ts +32 -0
- package/shared/errors.ts +12 -0
- package/shared/remaining-accounts.ts +41 -0
- package/shared/transactions.ts +49 -0
- package/short/builders.ts +268 -0
- package/short/claim-premium.ts +37 -0
- package/short/close-option.ts +34 -0
- package/short/pool.ts +224 -0
- package/tsconfig.json +12 -0
package/long/builders.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBuyFromPoolInstructionAsync,
|
|
3
|
+
getCloseLongToPoolInstructionAsync,
|
|
4
|
+
} from "../generated/instructions";
|
|
5
|
+
import type { Instruction } from "@solana/kit";
|
|
6
|
+
import { toAddress } from "../client/program";
|
|
7
|
+
import type { AddressLike, BuiltTransaction } from "../client/types";
|
|
8
|
+
import { assertPositiveAmount } from "../shared/amounts";
|
|
9
|
+
import { invariant } from "../shared/errors";
|
|
10
|
+
import {
|
|
11
|
+
appendRemainingAccounts,
|
|
12
|
+
type RemainingAccountInput,
|
|
13
|
+
} from "../shared/remaining-accounts";
|
|
14
|
+
|
|
15
|
+
export interface BuildBuyFromPoolParams {
|
|
16
|
+
optionPool: AddressLike;
|
|
17
|
+
optionAccount: AddressLike;
|
|
18
|
+
longMint: AddressLike;
|
|
19
|
+
underlyingMint: AddressLike;
|
|
20
|
+
marketData: AddressLike;
|
|
21
|
+
priceUpdate: AddressLike;
|
|
22
|
+
buyer: AddressLike;
|
|
23
|
+
buyerPaymentAccount: AddressLike;
|
|
24
|
+
escrowLongAccount: AddressLike;
|
|
25
|
+
premiumVault: AddressLike;
|
|
26
|
+
quantity: bigint | number;
|
|
27
|
+
premiumAmount: bigint | number;
|
|
28
|
+
buyerPosition?: AddressLike;
|
|
29
|
+
buyerOptionAccount?: AddressLike;
|
|
30
|
+
remainingAccounts?: RemainingAccountInput[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface BuildCloseLongToPoolParams {
|
|
34
|
+
optionPool: AddressLike;
|
|
35
|
+
optionAccount: AddressLike;
|
|
36
|
+
collateralPool: AddressLike;
|
|
37
|
+
underlyingMint: AddressLike;
|
|
38
|
+
longMint: AddressLike;
|
|
39
|
+
escrowLongAccount: AddressLike;
|
|
40
|
+
premiumVault: AddressLike;
|
|
41
|
+
marketData: AddressLike;
|
|
42
|
+
priceUpdate: AddressLike;
|
|
43
|
+
buyer: AddressLike;
|
|
44
|
+
buyerLongAccount: AddressLike;
|
|
45
|
+
buyerPayoutAccount: AddressLike;
|
|
46
|
+
collateralVault: AddressLike;
|
|
47
|
+
quantity: bigint | number;
|
|
48
|
+
minPayoutAmount: bigint | number;
|
|
49
|
+
buyerPosition?: AddressLike;
|
|
50
|
+
omlpVault?: AddressLike;
|
|
51
|
+
remainingAccounts?: RemainingAccountInput[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function buildBuyFromPoolInstruction(
|
|
55
|
+
params: BuildBuyFromPoolParams
|
|
56
|
+
): Promise<Instruction<string>> {
|
|
57
|
+
assertPositiveAmount(params.quantity, "quantity");
|
|
58
|
+
assertPositiveAmount(params.premiumAmount, "premiumAmount");
|
|
59
|
+
|
|
60
|
+
const kitInstruction = await getBuyFromPoolInstructionAsync({
|
|
61
|
+
optionPool: toAddress(params.optionPool),
|
|
62
|
+
optionAccount: toAddress(params.optionAccount),
|
|
63
|
+
longMint: toAddress(params.longMint),
|
|
64
|
+
underlyingMint: toAddress(params.underlyingMint),
|
|
65
|
+
marketData: toAddress(params.marketData),
|
|
66
|
+
priceUpdate: toAddress(params.priceUpdate),
|
|
67
|
+
buyer: toAddress(params.buyer) as any,
|
|
68
|
+
buyerPosition: params.buyerPosition ? toAddress(params.buyerPosition) : undefined,
|
|
69
|
+
buyerOptionAccount: params.buyerOptionAccount
|
|
70
|
+
? toAddress(params.buyerOptionAccount)
|
|
71
|
+
: undefined,
|
|
72
|
+
buyerPaymentAccount: toAddress(params.buyerPaymentAccount),
|
|
73
|
+
escrowLongAccount: toAddress(params.escrowLongAccount),
|
|
74
|
+
premiumVault: toAddress(params.premiumVault),
|
|
75
|
+
quantity: params.quantity,
|
|
76
|
+
premiumAmount: params.premiumAmount,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return appendRemainingAccounts(kitInstruction, params.remainingAccounts);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function buildBuyFromPoolTransaction(
|
|
83
|
+
params: BuildBuyFromPoolParams
|
|
84
|
+
): Promise<BuiltTransaction> {
|
|
85
|
+
const instruction = await buildBuyFromPoolInstruction(params);
|
|
86
|
+
return { instructions: [instruction] };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function buildCloseLongToPoolInstruction(
|
|
90
|
+
params: BuildCloseLongToPoolParams
|
|
91
|
+
): Promise<Instruction<string>> {
|
|
92
|
+
assertPositiveAmount(params.quantity, "quantity");
|
|
93
|
+
invariant(
|
|
94
|
+
BigInt(params.minPayoutAmount) >= 0n,
|
|
95
|
+
"minPayoutAmount must be greater than or equal to zero."
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const kitInstruction = await getCloseLongToPoolInstructionAsync({
|
|
99
|
+
optionPool: toAddress(params.optionPool),
|
|
100
|
+
optionAccount: toAddress(params.optionAccount),
|
|
101
|
+
collateralPool: toAddress(params.collateralPool),
|
|
102
|
+
underlyingMint: toAddress(params.underlyingMint),
|
|
103
|
+
longMint: toAddress(params.longMint),
|
|
104
|
+
escrowLongAccount: toAddress(params.escrowLongAccount),
|
|
105
|
+
premiumVault: toAddress(params.premiumVault),
|
|
106
|
+
marketData: toAddress(params.marketData),
|
|
107
|
+
priceUpdate: toAddress(params.priceUpdate),
|
|
108
|
+
buyer: toAddress(params.buyer) as any,
|
|
109
|
+
buyerLongAccount: toAddress(params.buyerLongAccount),
|
|
110
|
+
buyerPayoutAccount: toAddress(params.buyerPayoutAccount),
|
|
111
|
+
collateralVault: toAddress(params.collateralVault),
|
|
112
|
+
buyerPosition: params.buyerPosition ? toAddress(params.buyerPosition) : undefined,
|
|
113
|
+
omlpVault: params.omlpVault ? toAddress(params.omlpVault) : undefined,
|
|
114
|
+
quantity: params.quantity,
|
|
115
|
+
minPayoutAmount: params.minPayoutAmount,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return appendRemainingAccounts(kitInstruction, params.remainingAccounts);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function buildCloseLongToPoolTransaction(
|
|
122
|
+
params: BuildCloseLongToPoolParams
|
|
123
|
+
): Promise<BuiltTransaction> {
|
|
124
|
+
const instruction = await buildCloseLongToPoolInstruction(params);
|
|
125
|
+
return { instructions: [instruction] };
|
|
126
|
+
}
|
package/long/exercise.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getOptionExerciseInstruction } from "../generated/instructions";
|
|
2
|
+
import type { Instruction } from "@solana/kit";
|
|
3
|
+
import { toAddress } from "../client/program";
|
|
4
|
+
import type { AddressLike, BuiltTransaction } from "../client/types";
|
|
5
|
+
|
|
6
|
+
export interface BuildOptionExerciseParams {
|
|
7
|
+
optionAccount: AddressLike;
|
|
8
|
+
positionAccount: AddressLike;
|
|
9
|
+
marketData: AddressLike;
|
|
10
|
+
underlyingMint: AddressLike;
|
|
11
|
+
priceUpdate: AddressLike;
|
|
12
|
+
buyerPaymentAccount: AddressLike;
|
|
13
|
+
makerCollateralAccount: AddressLike;
|
|
14
|
+
escrowState: AddressLike;
|
|
15
|
+
escrowTokenAccount: AddressLike;
|
|
16
|
+
escrowAuthority: AddressLike;
|
|
17
|
+
buyer: AddressLike;
|
|
18
|
+
tokenProgram?: AddressLike;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function buildOptionExerciseInstruction(
|
|
22
|
+
params: BuildOptionExerciseParams
|
|
23
|
+
): Instruction<string> {
|
|
24
|
+
return getOptionExerciseInstruction({
|
|
25
|
+
optionAccount: toAddress(params.optionAccount),
|
|
26
|
+
positionAccount: toAddress(params.positionAccount),
|
|
27
|
+
marketData: toAddress(params.marketData),
|
|
28
|
+
underlyingMint: toAddress(params.underlyingMint),
|
|
29
|
+
priceUpdate: toAddress(params.priceUpdate),
|
|
30
|
+
buyerPaymentAccount: toAddress(params.buyerPaymentAccount),
|
|
31
|
+
makerCollateralAccount: toAddress(params.makerCollateralAccount),
|
|
32
|
+
escrowState: toAddress(params.escrowState),
|
|
33
|
+
escrowTokenAccount: toAddress(params.escrowTokenAccount),
|
|
34
|
+
escrowAuthority: toAddress(params.escrowAuthority),
|
|
35
|
+
buyer: toAddress(params.buyer) as any,
|
|
36
|
+
tokenProgram: params.tokenProgram ? toAddress(params.tokenProgram) : undefined,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Builds an option exercise transaction instruction set.
|
|
42
|
+
* Use `priceUpdate` from a fresh Pyth receiver update for accurate exercise pricing.
|
|
43
|
+
*/
|
|
44
|
+
export function buildOptionExerciseTransaction(
|
|
45
|
+
params: BuildOptionExerciseParams
|
|
46
|
+
): BuiltTransaction {
|
|
47
|
+
const instruction = buildOptionExerciseInstruction(params);
|
|
48
|
+
return { instructions: [instruction] };
|
|
49
|
+
}
|
package/long/quotes.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { assertPositiveAmount } from "../shared/amounts";
|
|
2
|
+
import { SdkValidationError } from "../shared/errors";
|
|
3
|
+
|
|
4
|
+
export function applySlippageBps(amount: bigint | number, slippageBps: number): bigint {
|
|
5
|
+
if (slippageBps < 0) {
|
|
6
|
+
throw new SdkValidationError("slippageBps cannot be negative.");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const base = BigInt(amount);
|
|
10
|
+
return (base * BigInt(10_000 + slippageBps)) / 10_000n;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function applyMinSlippageBps(amount: bigint | number, slippageBps: number): bigint {
|
|
14
|
+
if (slippageBps < 0) {
|
|
15
|
+
throw new SdkValidationError("slippageBps cannot be negative.");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const base = BigInt(amount);
|
|
19
|
+
return (base * BigInt(10_000 - slippageBps)) / 10_000n;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function buildBuyQuote(params: {
|
|
23
|
+
quantity: bigint | number;
|
|
24
|
+
premiumPerContract: bigint | number;
|
|
25
|
+
maxSlippageBps: number;
|
|
26
|
+
}): { expectedPremium: bigint; maxPremium: bigint } {
|
|
27
|
+
assertPositiveAmount(params.quantity, "quantity");
|
|
28
|
+
assertPositiveAmount(params.premiumPerContract, "premiumPerContract");
|
|
29
|
+
|
|
30
|
+
const expectedPremium = BigInt(params.quantity) * BigInt(params.premiumPerContract);
|
|
31
|
+
return {
|
|
32
|
+
expectedPremium,
|
|
33
|
+
maxPremium: applySlippageBps(expectedPremium, params.maxSlippageBps),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function buildCloseQuote(params: {
|
|
38
|
+
expectedPayout: bigint | number;
|
|
39
|
+
maxSlippageBps: number;
|
|
40
|
+
}): { expectedPayout: bigint; minPayout: bigint } {
|
|
41
|
+
assertPositiveAmount(params.expectedPayout, "expectedPayout");
|
|
42
|
+
|
|
43
|
+
const expectedPayout = BigInt(params.expectedPayout);
|
|
44
|
+
return {
|
|
45
|
+
expectedPayout,
|
|
46
|
+
minPayout: applyMinSlippageBps(expectedPayout, params.maxSlippageBps),
|
|
47
|
+
};
|
|
48
|
+
}
|
package/omlp/builders.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getDepositToPositionInstructionAsync,
|
|
3
|
+
getWithdrawFromPositionInstructionAsync,
|
|
4
|
+
} from "../generated/instructions";
|
|
5
|
+
import type { Instruction } from "@solana/kit";
|
|
6
|
+
import { toAddress } from "../client/program";
|
|
7
|
+
import type { AddressLike, BuiltTransaction } from "../client/types";
|
|
8
|
+
import { assertPositiveAmount } from "../shared/amounts";
|
|
9
|
+
|
|
10
|
+
export interface BuildDepositToPositionParams {
|
|
11
|
+
vault: AddressLike;
|
|
12
|
+
lenderTokenAccount: AddressLike;
|
|
13
|
+
vaultTokenAccount: AddressLike;
|
|
14
|
+
lender: AddressLike;
|
|
15
|
+
amount: bigint | number;
|
|
16
|
+
position?: AddressLike;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface BuildWithdrawFromPositionParams {
|
|
20
|
+
vault: AddressLike;
|
|
21
|
+
vaultTokenAccount: AddressLike;
|
|
22
|
+
lenderTokenAccount: AddressLike;
|
|
23
|
+
lender: AddressLike;
|
|
24
|
+
amount: bigint | number;
|
|
25
|
+
position?: AddressLike;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function buildDepositToPositionInstruction(
|
|
29
|
+
params: BuildDepositToPositionParams
|
|
30
|
+
): Promise<Instruction<string>> {
|
|
31
|
+
assertPositiveAmount(params.amount, "amount");
|
|
32
|
+
|
|
33
|
+
const kitInstruction = await getDepositToPositionInstructionAsync({
|
|
34
|
+
position: params.position ? toAddress(params.position) : undefined,
|
|
35
|
+
vault: toAddress(params.vault),
|
|
36
|
+
lenderTokenAccount: toAddress(params.lenderTokenAccount),
|
|
37
|
+
vaultTokenAccount: toAddress(params.vaultTokenAccount),
|
|
38
|
+
lender: toAddress(params.lender) as any,
|
|
39
|
+
amount: params.amount,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return kitInstruction;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function buildDepositToPositionTransaction(
|
|
46
|
+
params: BuildDepositToPositionParams
|
|
47
|
+
): Promise<BuiltTransaction> {
|
|
48
|
+
const instruction = await buildDepositToPositionInstruction(params);
|
|
49
|
+
return { instructions: [instruction] };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function buildWithdrawFromPositionInstruction(
|
|
53
|
+
params: BuildWithdrawFromPositionParams
|
|
54
|
+
): Promise<Instruction<string>> {
|
|
55
|
+
assertPositiveAmount(params.amount, "amount");
|
|
56
|
+
|
|
57
|
+
const kitInstruction = await getWithdrawFromPositionInstructionAsync({
|
|
58
|
+
position: params.position ? toAddress(params.position) : undefined,
|
|
59
|
+
vault: toAddress(params.vault),
|
|
60
|
+
vaultTokenAccount: toAddress(params.vaultTokenAccount),
|
|
61
|
+
lenderTokenAccount: toAddress(params.lenderTokenAccount),
|
|
62
|
+
lender: toAddress(params.lender) as any,
|
|
63
|
+
amount: params.amount,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return kitInstruction;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function buildWithdrawFromPositionTransaction(
|
|
70
|
+
params: BuildWithdrawFromPositionParams
|
|
71
|
+
): Promise<BuiltTransaction> {
|
|
72
|
+
const instruction = await buildWithdrawFromPositionInstruction(params);
|
|
73
|
+
return { instructions: [instruction] };
|
|
74
|
+
}
|
package/omlp/service.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { fetchLenderPosition, fetchVault } from "../accounts/fetchers";
|
|
2
|
+
import type { KitRpc } from "../client/types";
|
|
3
|
+
import {
|
|
4
|
+
buildDepositToPositionTransaction,
|
|
5
|
+
buildWithdrawFromPositionTransaction,
|
|
6
|
+
type BuildDepositToPositionParams,
|
|
7
|
+
type BuildWithdrawFromPositionParams,
|
|
8
|
+
} from "./builders";
|
|
9
|
+
|
|
10
|
+
function positiveDiff(a: bigint, b: bigint): bigint {
|
|
11
|
+
return a > b ? a - b : 0n;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function depositToPosition(
|
|
15
|
+
params: BuildDepositToPositionParams
|
|
16
|
+
) {
|
|
17
|
+
return buildDepositToPositionTransaction(params);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function withdrawFromPosition(
|
|
21
|
+
params: BuildWithdrawFromPositionParams
|
|
22
|
+
) {
|
|
23
|
+
return buildWithdrawFromPositionTransaction(params);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function withdrawAllFromPosition(
|
|
27
|
+
rpc: KitRpc,
|
|
28
|
+
params: Omit<BuildWithdrawFromPositionParams, "amount"> & {
|
|
29
|
+
position: NonNullable<BuildWithdrawFromPositionParams["position"]>;
|
|
30
|
+
}
|
|
31
|
+
): Promise<{ instructions: Awaited<ReturnType<typeof buildWithdrawFromPositionTransaction>>["instructions"]; amount: bigint }> {
|
|
32
|
+
const [position, vault] = await Promise.all([
|
|
33
|
+
fetchLenderPosition(rpc, params.position),
|
|
34
|
+
fetchVault(rpc, params.vault),
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
if (!position) {
|
|
38
|
+
throw new Error("Lender position not found. Provide position PDA or deposit first.");
|
|
39
|
+
}
|
|
40
|
+
if (!vault) {
|
|
41
|
+
throw new Error("Vault account not found.");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const unclaimedInterest = positiveDiff(
|
|
45
|
+
position.totalInterestEarned,
|
|
46
|
+
position.interestClaimed
|
|
47
|
+
);
|
|
48
|
+
const userMax = position.deposited + unclaimedInterest;
|
|
49
|
+
const poolAvailable = positiveDiff(vault.totalLiquidity, vault.totalLoans);
|
|
50
|
+
const amount = userMax < poolAvailable ? userMax : poolAvailable;
|
|
51
|
+
if (amount <= 0n) {
|
|
52
|
+
throw new Error("No withdrawable balance available right now.");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const built = await buildWithdrawFromPositionTransaction({ ...params, amount });
|
|
56
|
+
return { instructions: built.instructions, amount };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function withdrawInterestFromPosition(
|
|
60
|
+
rpc: KitRpc,
|
|
61
|
+
params: Omit<BuildWithdrawFromPositionParams, "amount"> & {
|
|
62
|
+
position: NonNullable<BuildWithdrawFromPositionParams["position"]>;
|
|
63
|
+
}
|
|
64
|
+
): Promise<{ instructions: Awaited<ReturnType<typeof buildWithdrawFromPositionTransaction>>["instructions"]; amount: bigint }> {
|
|
65
|
+
const [position, vault] = await Promise.all([
|
|
66
|
+
fetchLenderPosition(rpc, params.position),
|
|
67
|
+
fetchVault(rpc, params.vault),
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
if (!position) {
|
|
71
|
+
throw new Error("Lender position not found. Provide position PDA or deposit first.");
|
|
72
|
+
}
|
|
73
|
+
if (!vault) {
|
|
74
|
+
throw new Error("Vault account not found.");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const unclaimedInterest = positiveDiff(
|
|
78
|
+
position.totalInterestEarned,
|
|
79
|
+
position.interestClaimed
|
|
80
|
+
);
|
|
81
|
+
const poolAvailable = positiveDiff(vault.totalLiquidity, vault.totalLoans);
|
|
82
|
+
const amount = unclaimedInterest < poolAvailable ? unclaimedInterest : poolAvailable;
|
|
83
|
+
if (amount <= 0n) {
|
|
84
|
+
throw new Error("No claimable interest available right now.");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const built = await buildWithdrawFromPositionTransaction({ ...params, amount });
|
|
88
|
+
return { instructions: built.instructions, amount };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const omlpBuilders = {
|
|
92
|
+
buildDepositToPositionTransaction,
|
|
93
|
+
buildWithdrawFromPositionTransaction,
|
|
94
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@epicentral/sos-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Solana Option Standard SDK. The frontend-first SDK for Native Options Trading on Solana. Created by Epicentral Labs.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./index.ts",
|
|
9
|
+
"types": "./index.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./index.ts",
|
|
12
|
+
"./*": "./*"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"typecheck": "tsc --project tsconfig.json --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@solana/kit": "^6.1.0",
|
|
19
|
+
"bs58": "^6.0.0",
|
|
20
|
+
"decimal.js": "^10.4.3"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Decimal from "decimal.js";
|
|
2
|
+
import { SdkValidationError } from "./errors";
|
|
3
|
+
|
|
4
|
+
export function toBaseUnits(amount: Decimal.Value, decimals: number): bigint {
|
|
5
|
+
const scaled = new Decimal(amount).mul(new Decimal(10).pow(decimals));
|
|
6
|
+
return BigInt(scaled.floor().toFixed(0));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function fromBaseUnits(amount: bigint | number, decimals: number): Decimal {
|
|
10
|
+
return new Decimal(amount.toString()).div(new Decimal(10).pow(decimals));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function assertPositiveAmount(value: bigint | number, label: string): void {
|
|
14
|
+
const bigintValue = typeof value === "bigint" ? value : BigInt(value);
|
|
15
|
+
if (bigintValue <= 0n) {
|
|
16
|
+
throw new SdkValidationError(`${label} must be greater than zero.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function assertNonNegativeAmount(value: bigint | number, label: string): void {
|
|
21
|
+
const bigintValue = typeof value === "bigint" ? value : BigInt(value);
|
|
22
|
+
if (bigintValue < 0n) {
|
|
23
|
+
throw new SdkValidationError(`${label} cannot be negative.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function calculateRequiredCollateral(
|
|
28
|
+
quantity: bigint | number,
|
|
29
|
+
strikePrice: number
|
|
30
|
+
): number {
|
|
31
|
+
return Number(quantity) * 100 * strikePrice;
|
|
32
|
+
}
|
package/shared/errors.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class SdkValidationError extends Error {
|
|
2
|
+
constructor(message: string) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "SdkValidationError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function invariant(condition: boolean, message: string): asserts condition {
|
|
9
|
+
if (!condition) {
|
|
10
|
+
throw new SdkValidationError(message);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AccountRole, type AccountMeta, type Instruction } from "@solana/kit";
|
|
2
|
+
import { toAddress } from "../client/program";
|
|
3
|
+
import type { AddressLike } from "../client/types";
|
|
4
|
+
|
|
5
|
+
export interface RemainingAccountInput {
|
|
6
|
+
address: AddressLike;
|
|
7
|
+
isWritable: boolean;
|
|
8
|
+
isSigner?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function toAccountRole(input: RemainingAccountInput): AccountRole {
|
|
12
|
+
if (input.isWritable) {
|
|
13
|
+
return input.isSigner ? AccountRole.WRITABLE_SIGNER : AccountRole.WRITABLE;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return input.isSigner ? AccountRole.READONLY_SIGNER : AccountRole.READONLY;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function appendRemainingAccounts(
|
|
20
|
+
instruction: Instruction<string>,
|
|
21
|
+
remainingAccounts: RemainingAccountInput[] | undefined
|
|
22
|
+
): Instruction<string> {
|
|
23
|
+
if (!remainingAccounts?.length) {
|
|
24
|
+
return instruction;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const extras = remainingAccounts.map(
|
|
28
|
+
(account) =>
|
|
29
|
+
({
|
|
30
|
+
address: toAddress(account.address),
|
|
31
|
+
role: toAccountRole(account),
|
|
32
|
+
}) as AccountMeta<string>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const existingAccounts = instruction.accounts ?? [];
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
...instruction,
|
|
39
|
+
accounts: [...existingAccounts, ...extras],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendTransactionMessageInstructions,
|
|
3
|
+
createTransactionMessage,
|
|
4
|
+
getSignatureFromTransaction,
|
|
5
|
+
pipe,
|
|
6
|
+
sendAndConfirmTransactionFactory,
|
|
7
|
+
setTransactionMessageFeePayerSigner,
|
|
8
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
9
|
+
signTransactionMessageWithSigners,
|
|
10
|
+
type RpcSubscriptions,
|
|
11
|
+
type SolanaRpcSubscriptionsApi,
|
|
12
|
+
type TransactionSigner,
|
|
13
|
+
} from "@solana/kit";
|
|
14
|
+
import type { BuiltTransaction, KitRpc } from "../client/types";
|
|
15
|
+
|
|
16
|
+
export interface SendBuiltTransactionParams extends BuiltTransaction {
|
|
17
|
+
rpc: KitRpc;
|
|
18
|
+
rpcSubscriptions: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
|
|
19
|
+
feePayer: TransactionSigner<string>;
|
|
20
|
+
commitment?: "processed" | "confirmed" | "finalized";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Sends a built SDK transaction with common Solana Kit defaults.
|
|
25
|
+
* The caller still controls the RPC clients and fee-payer signer.
|
|
26
|
+
*/
|
|
27
|
+
export async function sendBuiltTransaction(
|
|
28
|
+
params: SendBuiltTransactionParams
|
|
29
|
+
): Promise<string> {
|
|
30
|
+
const commitment = params.commitment ?? "confirmed";
|
|
31
|
+
const { value: latestBlockhash } = await params.rpc.getLatestBlockhash().send();
|
|
32
|
+
|
|
33
|
+
const txMessage = pipe(
|
|
34
|
+
createTransactionMessage({ version: 0 }),
|
|
35
|
+
(tx) => setTransactionMessageFeePayerSigner(params.feePayer, tx),
|
|
36
|
+
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
37
|
+
(tx) => appendTransactionMessageInstructions(params.instructions, tx)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const signedTx = await signTransactionMessageWithSigners(txMessage);
|
|
41
|
+
const sendAndConfirm = sendAndConfirmTransactionFactory({
|
|
42
|
+
rpc: params.rpc,
|
|
43
|
+
rpcSubscriptions: params.rpcSubscriptions,
|
|
44
|
+
});
|
|
45
|
+
type SendableTransaction = Parameters<typeof sendAndConfirm>[0];
|
|
46
|
+
|
|
47
|
+
await sendAndConfirm(signedTx as SendableTransaction, { commitment });
|
|
48
|
+
return getSignatureFromTransaction(signedTx);
|
|
49
|
+
}
|