@epicentral/sos-sdk 0.9.0-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.
Files changed (113) hide show
  1. package/.env.example +1 -0
  2. package/AGENTS.md +7 -0
  3. package/LICENSE +21 -0
  4. package/README.md +568 -0
  5. package/accounts/fetchers.ts +196 -0
  6. package/accounts/list.ts +184 -0
  7. package/accounts/pdas.ts +325 -0
  8. package/accounts/resolve-option.ts +104 -0
  9. package/client/lookup-table.ts +114 -0
  10. package/client/program.ts +13 -0
  11. package/client/types.ts +9 -0
  12. package/generated/accounts/collateralPool.ts +217 -0
  13. package/generated/accounts/config.ts +156 -0
  14. package/generated/accounts/escrowState.ts +183 -0
  15. package/generated/accounts/index.ts +20 -0
  16. package/generated/accounts/lenderPosition.ts +211 -0
  17. package/generated/accounts/makerCollateralShare.ts +229 -0
  18. package/generated/accounts/marketDataAccount.ts +176 -0
  19. package/generated/accounts/optionAccount.ts +247 -0
  20. package/generated/accounts/optionPool.ts +285 -0
  21. package/generated/accounts/poolLoan.ts +232 -0
  22. package/generated/accounts/positionAccount.ts +201 -0
  23. package/generated/accounts/vault.ts +366 -0
  24. package/generated/accounts/writerPosition.ts +327 -0
  25. package/generated/errors/index.ts +9 -0
  26. package/generated/errors/optionProgram.ts +476 -0
  27. package/generated/index.ts +13 -0
  28. package/generated/instructions/acceptAdmin.ts +230 -0
  29. package/generated/instructions/autoExerciseAllExpired.ts +685 -0
  30. package/generated/instructions/autoExerciseExpired.ts +754 -0
  31. package/generated/instructions/borrowFromPool.ts +619 -0
  32. package/generated/instructions/buyFromPool.ts +761 -0
  33. package/generated/instructions/closeLongToPool.ts +762 -0
  34. package/generated/instructions/closeOption.ts +235 -0
  35. package/generated/instructions/createEscrowV2.ts +518 -0
  36. package/generated/instructions/depositCollateral.ts +624 -0
  37. package/generated/instructions/depositToPosition.ts +429 -0
  38. package/generated/instructions/index.ts +47 -0
  39. package/generated/instructions/initCollateralPool.ts +513 -0
  40. package/generated/instructions/initConfig.ts +279 -0
  41. package/generated/instructions/initOptionPool.ts +587 -0
  42. package/generated/instructions/initializeMarketData.ts +359 -0
  43. package/generated/instructions/liquidateWriterPosition.ts +750 -0
  44. package/generated/instructions/liquidateWriterPositionRescue.ts +623 -0
  45. package/generated/instructions/omlpCreateVault.ts +553 -0
  46. package/generated/instructions/omlpUpdateFeeWallet.ts +473 -0
  47. package/generated/instructions/omlpUpdateInterestModel.ts +322 -0
  48. package/generated/instructions/omlpUpdateLiquidationThreshold.ts +304 -0
  49. package/generated/instructions/omlpUpdateMaintenanceBuffer.ts +304 -0
  50. package/generated/instructions/omlpUpdateMaxBorrowCap.ts +304 -0
  51. package/generated/instructions/omlpUpdateMaxLeverage.ts +304 -0
  52. package/generated/instructions/omlpUpdateProtocolFee.ts +304 -0
  53. package/generated/instructions/omlpUpdateSupplyLimit.ts +304 -0
  54. package/generated/instructions/optionExercise.ts +617 -0
  55. package/generated/instructions/optionMint.ts +1373 -0
  56. package/generated/instructions/optionValidate.ts +302 -0
  57. package/generated/instructions/repayPoolLoan.ts +558 -0
  58. package/generated/instructions/repayPoolLoanFromCollateral.ts +514 -0
  59. package/generated/instructions/repayPoolLoanFromWallet.ts +542 -0
  60. package/generated/instructions/settleMakerCollateral.ts +509 -0
  61. package/generated/instructions/syncWriterPosition.ts +206 -0
  62. package/generated/instructions/transferAdmin.ts +245 -0
  63. package/generated/instructions/unwindWriterUnsold.ts +764 -0
  64. package/generated/instructions/updateImpliedVolatility.ts +226 -0
  65. package/generated/instructions/updateMarketData.ts +315 -0
  66. package/generated/instructions/withdrawFromPosition.ts +405 -0
  67. package/generated/instructions/writeToPool.ts +619 -0
  68. package/generated/programs/index.ts +9 -0
  69. package/generated/programs/optionProgram.ts +1144 -0
  70. package/generated/shared/index.ts +164 -0
  71. package/generated/types/impliedVolatilityUpdated.ts +73 -0
  72. package/generated/types/index.ts +28 -0
  73. package/generated/types/liquidationExecuted.ts +73 -0
  74. package/generated/types/liquidationRescueEvent.ts +82 -0
  75. package/generated/types/marketDataInitialized.ts +61 -0
  76. package/generated/types/marketDataUpdated.ts +69 -0
  77. package/generated/types/optionClosed.ts +56 -0
  78. package/generated/types/optionExercised.ts +62 -0
  79. package/generated/types/optionExpired.ts +49 -0
  80. package/generated/types/optionMinted.ts +78 -0
  81. package/generated/types/optionType.ts +38 -0
  82. package/generated/types/optionValidated.ts +82 -0
  83. package/generated/types/poolLoanCreated.ts +74 -0
  84. package/generated/types/poolLoanRepaid.ts +74 -0
  85. package/generated/types/positionDeposited.ts +73 -0
  86. package/generated/types/positionWithdrawn.ts +81 -0
  87. package/generated/types/protocolFeeUpdated.ts +69 -0
  88. package/generated/types/vaultCreated.ts +60 -0
  89. package/generated/types/vaultFeeWalletUpdated.ts +67 -0
  90. package/generated/types/vaultInterestModelUpdated.ts +77 -0
  91. package/generated/types/vaultLiquidationThresholdUpdated.ts +69 -0
  92. package/index.ts +68 -0
  93. package/long/builders.ts +690 -0
  94. package/long/exercise.ts +123 -0
  95. package/long/preflight.ts +214 -0
  96. package/long/quotes.ts +48 -0
  97. package/long/remaining-accounts.ts +111 -0
  98. package/omlp/builders.ts +94 -0
  99. package/omlp/service.ts +136 -0
  100. package/oracle/switchboard.ts +315 -0
  101. package/package.json +34 -0
  102. package/shared/amounts.ts +53 -0
  103. package/shared/balances.ts +57 -0
  104. package/shared/errors.ts +12 -0
  105. package/shared/remaining-accounts.ts +41 -0
  106. package/shared/trade-config.ts +27 -0
  107. package/shared/transactions.ts +121 -0
  108. package/short/builders.ts +874 -0
  109. package/short/close-option.ts +34 -0
  110. package/short/pool.ts +189 -0
  111. package/short/preflight.ts +619 -0
  112. package/tsconfig.json +13 -0
  113. package/wsol/instructions.ts +247 -0
@@ -0,0 +1,196 @@
1
+ import {
2
+ getCollateralPoolDecoder,
3
+ getLenderPositionDecoder,
4
+ getMarketDataAccountDecoder,
5
+ getOptionAccountDecoder,
6
+ getOptionPoolDecoder,
7
+ getPoolLoanDecoder,
8
+ getPositionAccountDecoder,
9
+ getVaultDecoder,
10
+ getWriterPositionDecoder,
11
+ type CollateralPool,
12
+ type LenderPosition,
13
+ type MarketDataAccount,
14
+ type OptionAccount,
15
+ type OptionPool,
16
+ type PoolLoan,
17
+ type PositionAccount,
18
+ type Vault,
19
+ type WriterPosition,
20
+ } from "../generated/accounts";
21
+ import type { Address } from "@solana/kit";
22
+ import { toAddress } from "../client/program";
23
+ import type { AddressLike, KitRpc } from "../client/types";
24
+
25
+ async function fetchRawAccount(
26
+ rpc: KitRpc,
27
+ address: AddressLike
28
+ ): Promise<Uint8Array | null> {
29
+ const response = await rpc.getAccountInfo(toAddress(address), { encoding: "base64" }).send();
30
+ const accountInfo = response.value;
31
+ if (!accountInfo) return null;
32
+ const [data] = accountInfo.data;
33
+ const binary = atob(data);
34
+ const bytes = new Uint8Array(binary.length);
35
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
36
+ return bytes;
37
+ }
38
+
39
+ async function decodeAccount<T>(
40
+ rpc: KitRpc,
41
+ address: AddressLike,
42
+ decoder: { decode: (value: Uint8Array) => T }
43
+ ): Promise<T | null> {
44
+ const data = await fetchRawAccount(rpc, address);
45
+ if (!data) return null;
46
+ try {
47
+ return decoder.decode(data);
48
+ } catch (e) {
49
+ // #region agent log
50
+ try {
51
+ fetch("http://127.0.0.1:7586/ingest/4a07cb33-954d-4b27-b1a3-08f1423b9d05", {
52
+ method: "POST",
53
+ headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "af65cf" },
54
+ body: JSON.stringify({
55
+ sessionId: "af65cf",
56
+ location: "sos-sdk/accounts/fetchers.ts:decodeAccount",
57
+ message: "decode_throw",
58
+ data: {
59
+ address: String(address),
60
+ dataLen: data.length,
61
+ firstDiscHex: Array.from(data.slice(0, 8))
62
+ .map((b) => b.toString(16).padStart(2, "0"))
63
+ .join(""),
64
+ err: (e as Error)?.message ?? String(e),
65
+ },
66
+ timestamp: Date.now(),
67
+ hypothesisId: "H2-i64-account-size-mismatch",
68
+ }),
69
+ }).catch(() => {});
70
+ } catch {}
71
+ // #endregion
72
+ throw e;
73
+ }
74
+ }
75
+
76
+ export async function fetchOptionAccount(
77
+ rpc: KitRpc,
78
+ optionAccount: AddressLike
79
+ ): Promise<OptionAccount | null> {
80
+ return decodeAccount(rpc, optionAccount, getOptionAccountDecoder());
81
+ }
82
+
83
+ export async function fetchOptionPool(
84
+ rpc: KitRpc,
85
+ optionPool: AddressLike
86
+ ): Promise<OptionPool | null> {
87
+ return decodeAccount(rpc, optionPool, getOptionPoolDecoder());
88
+ }
89
+
90
+ export async function fetchCollateralPool(
91
+ rpc: KitRpc,
92
+ collateralPool: AddressLike
93
+ ): Promise<CollateralPool | null> {
94
+ return decodeAccount(rpc, collateralPool, getCollateralPoolDecoder());
95
+ }
96
+
97
+ export async function fetchWriterPosition(
98
+ rpc: KitRpc,
99
+ writerPosition: AddressLike
100
+ ): Promise<WriterPosition | null> {
101
+ return decodeAccount(rpc, writerPosition, getWriterPositionDecoder());
102
+ }
103
+
104
+ export async function fetchLenderPosition(
105
+ rpc: KitRpc,
106
+ lenderPosition: AddressLike
107
+ ): Promise<LenderPosition | null> {
108
+ return decodeAccount(rpc, lenderPosition, getLenderPositionDecoder());
109
+ }
110
+
111
+ export async function fetchBuyerPosition(
112
+ rpc: KitRpc,
113
+ buyerPosition: AddressLike
114
+ ): Promise<PositionAccount | null> {
115
+ return decodeAccount(rpc, buyerPosition, getPositionAccountDecoder());
116
+ }
117
+
118
+ export async function fetchVault(
119
+ rpc: KitRpc,
120
+ vault: AddressLike
121
+ ): Promise<Vault | null> {
122
+ return decodeAccount(rpc, vault, getVaultDecoder());
123
+ }
124
+
125
+ export async function fetchMarketDataAccount(
126
+ rpc: KitRpc,
127
+ marketData: AddressLike
128
+ ): Promise<MarketDataAccount | null> {
129
+ return decodeAccount(rpc, marketData, getMarketDataAccountDecoder());
130
+ }
131
+
132
+ export async function fetchPoolLoan(
133
+ rpc: KitRpc,
134
+ poolLoan: AddressLike
135
+ ): Promise<PoolLoan | null> {
136
+ return decodeAccount(rpc, poolLoan, getPoolLoanDecoder());
137
+ }
138
+
139
+ export async function accountExists(
140
+ rpc: KitRpc,
141
+ address: AddressLike
142
+ ): Promise<boolean> {
143
+ const response = await rpc.getAccountInfo(toAddress(address), { encoding: "base64" }).send();
144
+ return response.value !== null;
145
+ }
146
+
147
+ export async function fetchManyAccounts(
148
+ rpc: KitRpc,
149
+ addresses: AddressLike[]
150
+ ): Promise<Array<{ address: Address; exists: boolean }>> {
151
+ const keys = addresses.map((value) => toAddress(value));
152
+ const response = await rpc.getMultipleAccounts(keys, { encoding: "base64" }).send();
153
+ const infos = response.value;
154
+ return keys.map((key, index) => ({
155
+ address: key,
156
+ exists: infos[index] !== null,
157
+ }));
158
+ }
159
+
160
+ const optionDecoder = getOptionAccountDecoder();
161
+
162
+ /**
163
+ * Batch-fetches option accounts via getMultipleAccounts (one RPC round-trip).
164
+ * Returns a Map from address to OptionAccount or null if missing/invalid.
165
+ */
166
+ export async function fetchOptionAccounts(
167
+ rpc: KitRpc,
168
+ addresses: AddressLike[]
169
+ ): Promise<Map<Address, OptionAccount | null>> {
170
+ if (addresses.length === 0) return new Map();
171
+ const keys = addresses.map((value) => toAddress(value));
172
+ const response = await rpc.getMultipleAccounts(keys, { encoding: "base64" }).send();
173
+ const infos = response.value;
174
+ const result = new Map<Address, OptionAccount | null>();
175
+ for (let i = 0; i < keys.length; i++) {
176
+ const accountInfo = infos[i];
177
+ if (!accountInfo) {
178
+ result.set(keys[i], null);
179
+ continue;
180
+ }
181
+ const [b64] = accountInfo.data;
182
+ if (!b64) {
183
+ result.set(keys[i], null);
184
+ continue;
185
+ }
186
+ const binary = atob(b64);
187
+ const data = new Uint8Array(binary.length);
188
+ for (let j = 0; j < binary.length; j++) data[j] = binary.charCodeAt(j);
189
+ try {
190
+ result.set(keys[i], optionDecoder.decode(data));
191
+ } catch {
192
+ result.set(keys[i], null);
193
+ }
194
+ }
195
+ return result;
196
+ }
@@ -0,0 +1,184 @@
1
+ import bs58 from "bs58";
2
+ import type { Address } from "@solana/kit";
3
+ import {
4
+ OPTION_POOL_DISCRIMINATOR,
5
+ POOL_LOAN_DISCRIMINATOR,
6
+ POSITION_ACCOUNT_DISCRIMINATOR,
7
+ VAULT_DISCRIMINATOR,
8
+ WRITER_POSITION_DISCRIMINATOR,
9
+ getOptionPoolDecoder,
10
+ getOptionPoolSize,
11
+ getPoolLoanDecoder,
12
+ getPoolLoanSize,
13
+ getPositionAccountDecoder,
14
+ getPositionAccountSize,
15
+ getVaultDecoder,
16
+ getVaultSize,
17
+ getWriterPositionDecoder,
18
+ getWriterPositionSize,
19
+ type OptionPool,
20
+ type PoolLoan,
21
+ type PositionAccount,
22
+ type Vault,
23
+ type WriterPosition,
24
+ } from "../generated/accounts";
25
+ import { PROGRAM_ID, toAddress } from "../client/program";
26
+ import type { AddressLike, KitRpc } from "../client/types";
27
+
28
+ const DISCRIMINATOR_OFFSET = 0n;
29
+ const OWNER_OFFSET = 8n;
30
+ /** WriterPosition layout: discriminator(8) + writer_authority(32) + option_pool(32). Used for getProgramAccounts memcmp. */
31
+ const WRITER_POSITION_OPTION_POOL_OFFSET = 40n;
32
+ const ACTIVE_POOL_LOAN_STATUS = 1;
33
+
34
+ type ListedAccount<T> = {
35
+ address: Address;
36
+ data: T;
37
+ };
38
+
39
+ type ProgramAccountResponse = {
40
+ pubkey: Address;
41
+ account: {
42
+ data: [string, string] | string;
43
+ };
44
+ };
45
+
46
+ function decodeBase64Data(data: string): Uint8Array {
47
+ const binary = atob(data);
48
+ const bytes = new Uint8Array(binary.length);
49
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
50
+ return bytes;
51
+ }
52
+
53
+ function discriminatorFilter(discriminator: Uint8Array) {
54
+ return {
55
+ memcmp: {
56
+ offset: DISCRIMINATOR_OFFSET,
57
+ encoding: "base58",
58
+ bytes: bs58.encode(discriminator),
59
+ },
60
+ } as const;
61
+ }
62
+
63
+ function ownerFilter(owner: AddressLike) {
64
+ return {
65
+ memcmp: {
66
+ offset: OWNER_OFFSET,
67
+ encoding: "base58",
68
+ bytes: toAddress(owner),
69
+ },
70
+ } as const;
71
+ }
72
+
73
+ function optionPoolFilter(optionPool: AddressLike) {
74
+ return {
75
+ memcmp: {
76
+ offset: WRITER_POSITION_OPTION_POOL_OFFSET,
77
+ encoding: "base58",
78
+ bytes: toAddress(optionPool),
79
+ },
80
+ } as const;
81
+ }
82
+
83
+ async function fetchAndDecodeProgramAccounts<T>(
84
+ rpc: KitRpc,
85
+ decoder: { decode: (value: Uint8Array) => T },
86
+ filters: ReadonlyArray<unknown>,
87
+ programAddress: AddressLike = PROGRAM_ID
88
+ ): Promise<Array<ListedAccount<T>>> {
89
+ const response = await rpc
90
+ .getProgramAccounts(toAddress(programAddress), {
91
+ encoding: "base64",
92
+ filters: filters as never,
93
+ })
94
+ .send();
95
+
96
+ const rawAccounts = Array.isArray(response)
97
+ ? (response as Array<ProgramAccountResponse>)
98
+ : (response as { value: Array<ProgramAccountResponse> }).value;
99
+
100
+ return rawAccounts.map(({ pubkey, account }) => {
101
+ const base64Data =
102
+ Array.isArray(account.data) ? account.data[0] : account.data;
103
+ return {
104
+ address: pubkey,
105
+ data: decoder.decode(decodeBase64Data(base64Data)),
106
+ };
107
+ });
108
+ }
109
+
110
+ export async function fetchWriterPositionsByWriter(
111
+ rpc: KitRpc,
112
+ writer: AddressLike
113
+ ): Promise<Array<ListedAccount<WriterPosition>>> {
114
+ return fetchAndDecodeProgramAccounts(rpc, getWriterPositionDecoder(), [
115
+ discriminatorFilter(WRITER_POSITION_DISCRIMINATOR),
116
+ ownerFilter(writer),
117
+ { dataSize: BigInt(getWriterPositionSize()) },
118
+ ]);
119
+ }
120
+
121
+ /**
122
+ * Fetches all WriterPosition accounts for a single option pool.
123
+ * WriterPosition layout: option_pool at offset 40, 32 bytes (memcmp filter).
124
+ */
125
+ export async function fetchWriterPositionsForPool(
126
+ rpc: KitRpc,
127
+ optionPool: AddressLike,
128
+ programId?: AddressLike
129
+ ): Promise<Array<ListedAccount<WriterPosition>>> {
130
+ return fetchAndDecodeProgramAccounts(
131
+ rpc,
132
+ getWriterPositionDecoder(),
133
+ [
134
+ discriminatorFilter(WRITER_POSITION_DISCRIMINATOR),
135
+ optionPoolFilter(optionPool),
136
+ { dataSize: BigInt(getWriterPositionSize()) },
137
+ ],
138
+ programId ?? PROGRAM_ID
139
+ );
140
+ }
141
+
142
+ export async function fetchPositionAccountsByBuyer(
143
+ rpc: KitRpc,
144
+ buyer: AddressLike
145
+ ): Promise<Array<ListedAccount<PositionAccount>>> {
146
+ return fetchAndDecodeProgramAccounts(rpc, getPositionAccountDecoder(), [
147
+ discriminatorFilter(POSITION_ACCOUNT_DISCRIMINATOR),
148
+ ownerFilter(buyer),
149
+ { dataSize: BigInt(getPositionAccountSize()) },
150
+ ]);
151
+ }
152
+
153
+ export async function fetchPoolLoansByMaker(
154
+ rpc: KitRpc,
155
+ maker: AddressLike
156
+ ): Promise<Array<ListedAccount<PoolLoan>>> {
157
+ const decoded = await fetchAndDecodeProgramAccounts(rpc, getPoolLoanDecoder(), [
158
+ discriminatorFilter(POOL_LOAN_DISCRIMINATOR),
159
+ ownerFilter(maker),
160
+ { dataSize: BigInt(getPoolLoanSize()) },
161
+ ]);
162
+ return decoded.filter(
163
+ (item: { address: Address; data: PoolLoan }) =>
164
+ item.data.status === ACTIVE_POOL_LOAN_STATUS
165
+ );
166
+ }
167
+
168
+ export async function fetchAllOptionPools(
169
+ rpc: KitRpc
170
+ ): Promise<Array<ListedAccount<OptionPool>>> {
171
+ return fetchAndDecodeProgramAccounts(rpc, getOptionPoolDecoder(), [
172
+ discriminatorFilter(OPTION_POOL_DISCRIMINATOR),
173
+ { dataSize: BigInt(getOptionPoolSize()) },
174
+ ]);
175
+ }
176
+
177
+ export async function fetchAllVaults(
178
+ rpc: KitRpc
179
+ ): Promise<Array<ListedAccount<Vault>>> {
180
+ return fetchAndDecodeProgramAccounts(rpc, getVaultDecoder(), [
181
+ discriminatorFilter(VAULT_DISCRIMINATOR),
182
+ { dataSize: BigInt(getVaultSize()) },
183
+ ]);
184
+ }
@@ -0,0 +1,325 @@
1
+ import { address, getAddressEncoder, getProgramDerivedAddress, type Address } from "@solana/kit";
2
+ import { OptionType } from "../generated/types";
3
+ import { PROGRAM_ID, toAddress } from "../client/program";
4
+ import type { AddressLike } from "../client/types";
5
+
6
+ const METADATA_PROGRAM_ADDRESS = address("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
7
+ const ASSOCIATED_TOKEN_PROGRAM_ADDRESS = address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
8
+ const TOKEN_PROGRAM_ADDRESS = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
9
+
10
+ function f64ToLeBytes(value: number): Uint8Array {
11
+ const bytes = new Uint8Array(8);
12
+ const view = new DataView(bytes.buffer);
13
+ view.setFloat64(0, value, true);
14
+ return bytes;
15
+ }
16
+
17
+ function i64ToLeBytes(value: bigint | number): Uint8Array {
18
+ const bytes = new Uint8Array(8);
19
+ const view = new DataView(bytes.buffer);
20
+ view.setBigInt64(0, BigInt(value), true);
21
+ return bytes;
22
+ }
23
+
24
+ function u64ToLeBytes(value: bigint | number): Uint8Array {
25
+ const bytes = new Uint8Array(8);
26
+ const view = new DataView(bytes.buffer);
27
+ view.setBigUint64(0, BigInt(value), true);
28
+ return bytes;
29
+ }
30
+
31
+ function optionTypeToU8(optionType: OptionType): number {
32
+ return optionType === OptionType.Call ? 0 : 1;
33
+ }
34
+
35
+ export async function deriveOptionAccountPda(params: {
36
+ underlyingAsset: AddressLike;
37
+ optionType: OptionType;
38
+ strikePrice: number;
39
+ expirationDate: bigint | number;
40
+ programId?: AddressLike;
41
+ }): Promise<readonly [Address, number]> {
42
+ const addressEncoder = getAddressEncoder();
43
+ const programAddress = params.programId ? toAddress(params.programId) : PROGRAM_ID;
44
+ return getProgramDerivedAddress({
45
+ programAddress,
46
+ seeds: [
47
+ new TextEncoder().encode("option"),
48
+ addressEncoder.encode(toAddress(params.underlyingAsset)),
49
+ Uint8Array.of(optionTypeToU8(params.optionType)),
50
+ f64ToLeBytes(params.strikePrice),
51
+ i64ToLeBytes(params.expirationDate),
52
+ ],
53
+ });
54
+ }
55
+
56
+ export async function deriveLongMintPda(
57
+ optionAccount: AddressLike,
58
+ programId: AddressLike = PROGRAM_ID
59
+ ): Promise<readonly [Address, number]> {
60
+ const addressEncoder = getAddressEncoder();
61
+ return getProgramDerivedAddress({
62
+ programAddress: toAddress(programId),
63
+ seeds: [
64
+ new TextEncoder().encode("long_mint"),
65
+ addressEncoder.encode(toAddress(optionAccount)),
66
+ ],
67
+ });
68
+ }
69
+
70
+ export async function deriveShortMintPda(
71
+ optionAccount: AddressLike,
72
+ programId: AddressLike = PROGRAM_ID
73
+ ): Promise<readonly [Address, number]> {
74
+ const addressEncoder = getAddressEncoder();
75
+ return getProgramDerivedAddress({
76
+ programAddress: toAddress(programId),
77
+ seeds: [
78
+ new TextEncoder().encode("short_mint"),
79
+ addressEncoder.encode(toAddress(optionAccount)),
80
+ ],
81
+ });
82
+ }
83
+
84
+ export async function deriveMintAuthorityPda(
85
+ programId: AddressLike = PROGRAM_ID
86
+ ): Promise<readonly [Address, number]> {
87
+ return getProgramDerivedAddress({
88
+ programAddress: toAddress(programId),
89
+ seeds: [new TextEncoder().encode("mint_authority")],
90
+ });
91
+ }
92
+
93
+ export async function deriveConfigPda(
94
+ programId: AddressLike = PROGRAM_ID
95
+ ): Promise<readonly [Address, number]> {
96
+ return getProgramDerivedAddress({
97
+ programAddress: toAddress(programId),
98
+ seeds: [new TextEncoder().encode("config")],
99
+ });
100
+ }
101
+
102
+ export async function deriveOptionPoolPda(
103
+ optionAccount: AddressLike,
104
+ programId: AddressLike = PROGRAM_ID
105
+ ): Promise<readonly [Address, number]> {
106
+ const addressEncoder = getAddressEncoder();
107
+ return getProgramDerivedAddress({
108
+ programAddress: toAddress(programId),
109
+ seeds: [
110
+ new TextEncoder().encode("option_pool"),
111
+ addressEncoder.encode(toAddress(optionAccount)),
112
+ ],
113
+ });
114
+ }
115
+
116
+ export async function deriveCollateralPoolPda(
117
+ optionAccount: AddressLike,
118
+ programId: AddressLike = PROGRAM_ID
119
+ ): Promise<readonly [Address, number]> {
120
+ const addressEncoder = getAddressEncoder();
121
+ return getProgramDerivedAddress({
122
+ programAddress: toAddress(programId),
123
+ seeds: [
124
+ new TextEncoder().encode("collateral_pool"),
125
+ addressEncoder.encode(toAddress(optionAccount)),
126
+ ],
127
+ });
128
+ }
129
+
130
+ export async function deriveWriterPositionPda(
131
+ optionPool: AddressLike,
132
+ writer: AddressLike,
133
+ programId: AddressLike = PROGRAM_ID
134
+ ): Promise<readonly [Address, number]> {
135
+ const addressEncoder = getAddressEncoder();
136
+ return getProgramDerivedAddress({
137
+ programAddress: toAddress(programId),
138
+ seeds: [
139
+ new TextEncoder().encode("writer_position"),
140
+ addressEncoder.encode(toAddress(optionPool)),
141
+ addressEncoder.encode(toAddress(writer)),
142
+ ],
143
+ });
144
+ }
145
+
146
+ export async function deriveMakerCollateralSharePda(
147
+ collateralPool: AddressLike,
148
+ maker: AddressLike,
149
+ programId: AddressLike = PROGRAM_ID
150
+ ): Promise<readonly [Address, number]> {
151
+ const addressEncoder = getAddressEncoder();
152
+ return getProgramDerivedAddress({
153
+ programAddress: toAddress(programId),
154
+ seeds: [
155
+ new TextEncoder().encode("maker_collateral_share"),
156
+ addressEncoder.encode(toAddress(collateralPool)),
157
+ addressEncoder.encode(toAddress(maker)),
158
+ ],
159
+ });
160
+ }
161
+
162
+ export async function deriveBuyerPositionPda(
163
+ buyer: AddressLike,
164
+ optionAccount: AddressLike,
165
+ programId: AddressLike = PROGRAM_ID
166
+ ): Promise<readonly [Address, number]> {
167
+ const addressEncoder = getAddressEncoder();
168
+ return getProgramDerivedAddress({
169
+ programAddress: toAddress(programId),
170
+ seeds: [
171
+ new TextEncoder().encode("position"),
172
+ addressEncoder.encode(toAddress(buyer)),
173
+ addressEncoder.encode(toAddress(optionAccount)),
174
+ ],
175
+ });
176
+ }
177
+
178
+ export async function deriveMetadataPda(mint: AddressLike): Promise<readonly [Address, number]> {
179
+ const addressEncoder = getAddressEncoder();
180
+ return getProgramDerivedAddress({
181
+ programAddress: METADATA_PROGRAM_ADDRESS,
182
+ seeds: [
183
+ new TextEncoder().encode("metadata"),
184
+ addressEncoder.encode(METADATA_PROGRAM_ADDRESS),
185
+ addressEncoder.encode(toAddress(mint)),
186
+ ],
187
+ });
188
+ }
189
+
190
+ export async function deriveMarketDataPda(
191
+ underlyingAsset: AddressLike,
192
+ programId: AddressLike = PROGRAM_ID
193
+ ): Promise<readonly [Address, number]> {
194
+ const addressEncoder = getAddressEncoder();
195
+ return getProgramDerivedAddress({
196
+ programAddress: toAddress(programId),
197
+ seeds: [
198
+ new TextEncoder().encode("market_data"),
199
+ addressEncoder.encode(toAddress(underlyingAsset)),
200
+ ],
201
+ });
202
+ }
203
+
204
+ export async function deriveVaultPda(
205
+ mint: AddressLike,
206
+ programId: AddressLike = PROGRAM_ID
207
+ ): Promise<readonly [Address, number]> {
208
+ const addressEncoder = getAddressEncoder();
209
+ return getProgramDerivedAddress({
210
+ programAddress: toAddress(programId),
211
+ seeds: [new TextEncoder().encode("vault"), addressEncoder.encode(toAddress(mint))],
212
+ });
213
+ }
214
+
215
+ export async function deriveLenderPositionPda(
216
+ vault: AddressLike,
217
+ lender: AddressLike,
218
+ programId: AddressLike = PROGRAM_ID
219
+ ): Promise<readonly [Address, number]> {
220
+ const addressEncoder = getAddressEncoder();
221
+ return getProgramDerivedAddress({
222
+ programAddress: toAddress(programId),
223
+ seeds: [
224
+ new TextEncoder().encode("lender_position"),
225
+ addressEncoder.encode(toAddress(vault)),
226
+ addressEncoder.encode(toAddress(lender)),
227
+ ],
228
+ });
229
+ }
230
+
231
+ export async function deriveEscrowStatePda(
232
+ maker: AddressLike,
233
+ collateralMint: AddressLike,
234
+ programId: AddressLike = PROGRAM_ID
235
+ ): Promise<readonly [Address, number]> {
236
+ const addressEncoder = getAddressEncoder();
237
+ return getProgramDerivedAddress({
238
+ programAddress: toAddress(programId),
239
+ seeds: [
240
+ new TextEncoder().encode("escrow_v2"),
241
+ addressEncoder.encode(toAddress(maker)),
242
+ addressEncoder.encode(toAddress(collateralMint)),
243
+ ],
244
+ });
245
+ }
246
+
247
+ export async function deriveEscrowAuthorityPda(
248
+ escrowState: AddressLike,
249
+ programId: AddressLike = PROGRAM_ID
250
+ ): Promise<readonly [Address, number]> {
251
+ const addressEncoder = getAddressEncoder();
252
+ return getProgramDerivedAddress({
253
+ programAddress: toAddress(programId),
254
+ seeds: [
255
+ new TextEncoder().encode("escrow_authority_v2"),
256
+ addressEncoder.encode(toAddress(escrowState)),
257
+ ],
258
+ });
259
+ }
260
+
261
+ /**
262
+ * Derives the PoolLoan PDA using the canonical seeds: vault, maker, nonce.
263
+ * Matches the program's derivation in omlp_context.rs (BorrowFromPool).
264
+ *
265
+ * @param vault - OMLP vault PDA (from deriveVaultPda)
266
+ * @param maker - Writer/borrower pubkey
267
+ * @param nonce - Loan nonce (u64)
268
+ * @param programId - Optional program ID
269
+ */
270
+ export async function derivePoolLoanPdaFromVault(
271
+ vault: AddressLike,
272
+ maker: AddressLike,
273
+ nonce: bigint | number,
274
+ programId: AddressLike = PROGRAM_ID
275
+ ): Promise<readonly [Address, number]> {
276
+ const addressEncoder = getAddressEncoder();
277
+ return getProgramDerivedAddress({
278
+ programAddress: toAddress(programId),
279
+ seeds: [
280
+ new TextEncoder().encode("pool_loan"),
281
+ addressEncoder.encode(toAddress(vault)),
282
+ addressEncoder.encode(toAddress(maker)),
283
+ u64ToLeBytes(nonce),
284
+ ],
285
+ });
286
+ }
287
+
288
+ /**
289
+ * Derives the PoolLoan PDA using writer position and nonce.
290
+ *
291
+ * @deprecated This derivation does not match the program. Use {@link derivePoolLoanPdaFromVault}
292
+ * with (vault, maker, nonce) instead. Program seeds are: pool_loan, vault, maker, nonce (u64 le).
293
+ */
294
+ export async function derivePoolLoanPda(
295
+ writerPosition: AddressLike,
296
+ nonce: bigint | number,
297
+ programId: AddressLike = PROGRAM_ID
298
+ ): Promise<readonly [Address, number]> {
299
+ const addressEncoder = getAddressEncoder();
300
+ return getProgramDerivedAddress({
301
+ programAddress: toAddress(programId),
302
+ seeds: [
303
+ new TextEncoder().encode("pool_loan"),
304
+ addressEncoder.encode(toAddress(writerPosition)),
305
+ u64ToLeBytes(nonce),
306
+ ],
307
+ });
308
+ }
309
+
310
+ export async function deriveAssociatedTokenAddress(
311
+ owner: AddressLike,
312
+ mint: AddressLike,
313
+ _allowOwnerOffCurve = false
314
+ ): Promise<Address> {
315
+ const addressEncoder = getAddressEncoder();
316
+ const [associatedTokenAddress] = await getProgramDerivedAddress({
317
+ programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
318
+ seeds: [
319
+ addressEncoder.encode(toAddress(owner)),
320
+ addressEncoder.encode(TOKEN_PROGRAM_ADDRESS),
321
+ addressEncoder.encode(toAddress(mint)),
322
+ ],
323
+ });
324
+ return associatedTokenAddress;
325
+ }