@epicentral/sos-sdk 0.2.11 → 0.2.13

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/accounts/list.ts CHANGED
@@ -27,6 +27,8 @@ import type { AddressLike, KitRpc } from "../client/types";
27
27
 
28
28
  const DISCRIMINATOR_OFFSET = 0n;
29
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;
30
32
  const ACTIVE_POOL_LOAN_STATUS = 1;
31
33
 
32
34
  type ListedAccount<T> = {
@@ -68,13 +70,24 @@ function ownerFilter(owner: AddressLike) {
68
70
  } as const;
69
71
  }
70
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
+
71
83
  async function fetchAndDecodeProgramAccounts<T>(
72
84
  rpc: KitRpc,
73
85
  decoder: { decode: (value: Uint8Array) => T },
74
- filters: ReadonlyArray<unknown>
86
+ filters: ReadonlyArray<unknown>,
87
+ programAddress: AddressLike = PROGRAM_ID
75
88
  ): Promise<Array<ListedAccount<T>>> {
76
89
  const response = await rpc
77
- .getProgramAccounts(PROGRAM_ID, {
90
+ .getProgramAccounts(toAddress(programAddress), {
78
91
  encoding: "base64",
79
92
  filters: filters as never,
80
93
  })
@@ -105,6 +118,27 @@ export async function fetchWriterPositionsByWriter(
105
118
  ]);
106
119
  }
107
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
+
108
142
  export async function fetchPositionAccountsByBuyer(
109
143
  rpc: KitRpc,
110
144
  buyer: AddressLike
package/index.ts CHANGED
@@ -17,6 +17,9 @@ export * from "./shared/transactions";
17
17
  export * from "./long/builders";
18
18
  export * from "./long/exercise";
19
19
  export * from "./long/quotes";
20
+ export {
21
+ getBuyFromPoolRemainingAccounts,
22
+ } from "./long/remaining-accounts";
20
23
 
21
24
  export * from "./short/builders";
22
25
  export * from "./short/claim-theta";
package/long/builders.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  type RemainingAccountInput,
18
18
  } from "../shared/remaining-accounts";
19
19
  import type { OptionType } from "../generated/types";
20
+ import { getCreateAssociatedTokenIdempotentInstructionWithAddress } from "../wsol/instructions";
20
21
 
21
22
  export interface BuildBuyFromPoolParams {
22
23
  optionPool: AddressLike;
@@ -85,11 +86,28 @@ export async function buildBuyFromPoolInstruction(
85
86
  return appendRemainingAccounts(kitInstruction, params.remainingAccounts);
86
87
  }
87
88
 
89
+ /**
90
+ * Builds a buy-from-pool transaction. The returned transaction may include a
91
+ * leading create-ATA-idempotent instruction for the buyer's option account so
92
+ * first-time buyers succeed without a separate setup step.
93
+ */
88
94
  export async function buildBuyFromPoolTransaction(
89
95
  params: BuildBuyFromPoolParams
90
96
  ): Promise<BuiltTransaction> {
91
- const instruction = await buildBuyFromPoolInstruction(params);
92
- return { instructions: [instruction] };
97
+ const buyerOptionAccountAddress = params.buyerOptionAccount
98
+ ? toAddress(params.buyerOptionAccount)
99
+ : await deriveAssociatedTokenAddress(params.buyer, params.longMint);
100
+
101
+ const createAtaIx =
102
+ await getCreateAssociatedTokenIdempotentInstructionWithAddress(
103
+ params.buyer,
104
+ params.buyer,
105
+ params.longMint,
106
+ buyerOptionAccountAddress
107
+ );
108
+
109
+ const buyFromPoolIx = await buildBuyFromPoolInstruction(params);
110
+ return { instructions: [createAtaIx, buyFromPoolIx] };
93
111
  }
94
112
 
95
113
  export interface BuildBuyFromPoolTransactionWithDerivationParams {
@@ -0,0 +1,31 @@
1
+ import type { RemainingAccountInput } from "../shared/remaining-accounts";
2
+ import type { AddressLike, KitRpc } from "../client/types";
3
+ import { PROGRAM_ID } from "../client/program";
4
+ import { fetchWriterPositionsForPool } from "../accounts/list";
5
+
6
+ /**
7
+ * Returns remaining_accounts for the buy_from_pool instruction: WriterPosition
8
+ * accounts for the given pool, sorted by unsoldQty ascending (smallest first),
9
+ * in the shape expected by buildBuyFromPoolTransaction and
10
+ * buildBuyFromPoolTransactionWithDerivation.
11
+ */
12
+ export async function getBuyFromPoolRemainingAccounts(
13
+ rpc: KitRpc,
14
+ optionPool: AddressLike,
15
+ programId?: AddressLike
16
+ ): Promise<RemainingAccountInput[]> {
17
+ const positions = await fetchWriterPositionsForPool(
18
+ rpc,
19
+ optionPool,
20
+ programId ?? PROGRAM_ID
21
+ );
22
+ const sorted = [...positions].sort((a, b) => {
23
+ const aQty = a.data.unsoldQty;
24
+ const bQty = b.data.unsoldQty;
25
+ return aQty < bQty ? -1 : aQty > bQty ? 1 : 0;
26
+ });
27
+ return sorted.map(({ address }) => ({
28
+ address,
29
+ isWritable: true,
30
+ }));
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicentral/sos-sdk",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
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",