@picon-finance/dlmm-sdk 1.18.2 → 1.18.3

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
@@ -1,6 +1,9 @@
1
1
  # @picon-finance/dlmm-sdk
2
2
 
3
- TypeScript SDK for the [Picon DLMM](https://github.com/picon-finance) protocol on Solana, built on [`@solana/kit`](https://github.com/anza-xyz/kit).
3
+ TypeScript SDK for the [Picon DLMM](https://github.com/picon-finance) protocol on Solana,
4
+ built on [`@solana/kit`](https://github.com/anza-xyz/kit).
5
+
6
+ Full protocol and integration docs: **[docs.picon.finance](https://docs.picon.finance)**.
4
7
 
5
8
  ## Install
6
9
 
@@ -23,9 +26,13 @@ supported consumption splits into two scenarios:
23
26
 
24
27
  ## Usage
25
28
 
26
- The SDK is built around stateful classes (`DlmmProgram`, `Pool`, `Position`, `BinArray`) that cache on-chain state to avoid redundant RPC round trips. Every method returns unsigned `Instruction`s (never signs or sends) — build, sign, and send the transaction yourself with `@solana/kit`.
29
+ The SDK is built around stateful classes — `DlmmProgram`, `Pool`, `Position`, `BinArray` — that
30
+ cache on-chain state to avoid redundant RPC round trips. Every method returns unsigned
31
+ `Instruction`s and never signs or sends; you build, sign, and send the transaction yourself with
32
+ `@solana/kit`.
27
33
 
28
- For low-level access — raw instruction builders, account decoders, PDA derivation — the Codama-generated client is exposed as `generated`, and used internally by the SDK itself.
34
+ For low-level access — raw instruction builders, account decoders, PDA derivation — the
35
+ Codama-generated client is exposed as `generated`, and used internally by the SDK itself.
29
36
 
30
37
  ```ts
31
38
  import {
@@ -39,12 +46,13 @@ import {
39
46
  sendAndConfirmTransactionFactory,
40
47
  createSolanaRpcSubscriptions,
41
48
  } from "@solana/kit";
42
- import { DlmmProgram, events, DistributionMode, DEVNET_PROGRAM_ADDRESS } from "@picon-finance/dlmm-sdk";
49
+ import { DlmmProgram, events, DistributionMode } from "@picon-finance/dlmm-sdk";
43
50
 
44
51
  const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
45
52
 
46
- // Omit programAddress to target mainnet; pass DEVNET_PROGRAM_ADDRESS (or your own) otherwise.
47
- const dlmmProgram = new DlmmProgram(rpc, DEVNET_PROGRAM_ADDRESS);
53
+ // Omit programAddress to target mainnet. Testing against devnet instead? Import
54
+ // DEVNET_PROGRAM_ADDRESS and pass it as the second argument here.
55
+ const dlmmProgram = new DlmmProgram(rpc);
48
56
 
49
57
  // Fetch and cache a pool's account data, mints, and token programs in one call.
50
58
  const pool = await dlmmProgram.getPool(poolAddress);
@@ -73,6 +81,8 @@ const signedTransaction = await signTransactionMessageWithSigners(transactionMes
73
81
 
74
82
  ### Positions
75
83
 
84
+ #### Open, deposit, claim, withdraw, close
85
+
76
86
  ```ts
77
87
  // Open a position and deposit in one flow.
78
88
  const openPositionIxs = await pool.openPosition(ownerSigner, positionMintSigner, {
@@ -102,13 +112,19 @@ const withdrawIxs = await position.withdraw(ownerSigner, { bpsToRemove: 5_000 })
102
112
  const closeIx = await position.close(ownerSigner);
103
113
  ```
104
114
 
105
- `position.data` exposes the decoded on-chain `Position` account (`pool`, `positionMint`, `lowerBinId`, `upperBinId`, `feeStates`, ...) directly from the cached account — no extra fetch needed:
115
+ #### Reading position state
116
+
117
+ `position.data` exposes the decoded on-chain `Position` account (`pool`, `positionMint`,
118
+ `lowerBinId`, `upperBinId`, `feeStates`, ...) directly from the cached account — no extra fetch
119
+ needed:
106
120
 
107
121
  ```ts
108
122
  console.log(position.data.lowerBinId, position.data.upperBinId);
109
123
  ```
110
124
 
111
- `position.getInfo()` returns a full summary: deposited amounts and the total fee a `claimFee` call would sweep right now, each in both `gross*` (before any Token-2022 transfer fee) and `net*` (what you'd actually receive) forms, plus the per-bin data they're summed from:
125
+ `position.getInfo()` returns a full summary: deposited amounts and the total fee a `claimFee`
126
+ call would sweep right now, each in both `gross*` (before any Token-2022 transfer fee) and
127
+ `net*` (what you'd actually receive) forms, plus the per-bin data they're summed from:
112
128
 
113
129
  ```ts
114
130
  const info = await position.getInfo();
@@ -116,7 +132,9 @@ console.log(`Deposited: ${info.netAmountX} X / ${info.netAmountY} Y`);
116
132
  console.log(`Claimable fee: ${info.netFeeX} X / ${info.netFeeY} Y`);
117
133
  ```
118
134
 
119
- `info.bins` (same as calling `position.getBinInfos()` directly) is the per-bin breakdown `getInfo()` sums to produce those totals — always raw, since `gross*`/`net*` only apply once, to the aggregate:
135
+ `info.bins` (same as calling `position.getBinInfos()` directly) is the per-bin breakdown
136
+ `getInfo()` sums to produce those totals. It's always raw — `gross*`/`net*` only apply once,
137
+ to the aggregate:
120
138
 
121
139
  ```ts
122
140
  for (const { bin, amountX, amountY, feeX, feeY } of position.getBinInfos()) {
@@ -124,21 +142,36 @@ for (const { bin, amountX, amountY, feeX, feeY } of position.getBinInfos()) {
124
142
  }
125
143
  ```
126
144
 
127
- Both are computed entirely from cached position + bin array data — `getBinInfos()` makes no RPC calls at all; `getInfo()` makes one round trip (via `Pool.getTransferFees()`) to resolve each mint's live transfer-fee rate.
145
+ Both are computed entirely from cached position + bin array data. `getBinInfos()` makes no RPC
146
+ calls at all; `getInfo()` makes one round trip (via `Pool.getTransferFees()`) to resolve each
147
+ mint's live transfer-fee rate.
128
148
 
129
- `Pool.getTransferFees()` resolves each mint's active [Token-2022 transfer-fee](https://spl.solana.com/token-2022/extensions#transfer-fees) config from cached mint data — `undefined` per side means that mint has no `TransferFeeConfig` extension, not that the fee is zero:
149
+ `Pool.getTransferFees()` resolves each mint's active
150
+ [Token-2022 transfer-fee](https://spl.solana.com/token-2022/extensions#transfer-fees) config
151
+ from cached mint data. `undefined` per side means that mint has no `TransferFeeConfig`
152
+ extension — not that the fee is zero:
130
153
 
131
154
  ```ts
132
155
  const { transferFeeX, transferFeeY } = await pool.getTransferFees();
133
156
  ```
134
157
 
135
- `Pool.getFeeRates(now?)` returns the base/dynamic/total fee rate the pool would charge for a swap at `now` (defaults to the current time) — decays the dynamic fee state first, the same "clock sim" the on-chain program runs right before pricing a real swap, so this reflects what a swap would actually pay rather than the raw, potentially stale, stored volatility accumulator:
158
+ `Pool.getFeeRates(now?)` returns the base/dynamic/total fee rate the pool would charge for a
159
+ swap at `now` (defaults to the current time). It decays the dynamic fee state first — the same
160
+ "clock sim" the on-chain program runs right before pricing a real swap — so this reflects what
161
+ a swap would actually pay, rather than the raw, potentially stale, stored volatility
162
+ accumulator:
136
163
 
137
164
  ```ts
138
165
  const { baseFeeRate, dynamicFeeRate, totalFeeRate } = await pool.getFeeRates();
139
166
  ```
140
167
 
141
- `swapExactIn`/`swapExactOut`/`quoteExactIn`/`quoteExactOut`/`sync` don't take a bin-array-count parameter — the quote methods always quote against the protocol max traversal window (`MAX_BIN_ARRAYS_PER_TRAVERSAL`) internally, then the matching swap method trims the bin-array set down to only what the quote says it actually needs (plus a one-array drift margin), so you never pay for more accounts than the trade is likely to touch:
168
+ #### Swaps and quotes
169
+
170
+ `swapExactIn`/`swapExactOut`/`quoteExactIn`/`quoteExactOut`/`sync` don't take a
171
+ bin-array-count parameter. The quote methods always quote against the protocol max traversal
172
+ window (`MAX_BIN_ARRAYS_PER_TRAVERSAL`) internally, then the matching swap method trims the
173
+ bin-array set down to only what the quote says it actually needs (plus a one-array drift
174
+ margin) — so you never pay for more accounts than the trade is likely to touch:
142
175
 
143
176
  ```ts
144
177
  // quoteExactIn() is a thin wrapper — same internal fetch/simulate/trim as swapExactIn(), just
@@ -161,9 +194,18 @@ const { quoteOutput: exactOutQuote, instructions: exactOutInstructions } = await
161
194
  });
162
195
  ```
163
196
 
164
- `Pool.sync(user, desiredBinId)` repositions the pool's active bin toward `desiredBinId` across empty bins only — also always uses the max traversal window, no count parameter.
197
+ `Pool.sync(user, desiredBinId)` repositions the pool's active bin toward `desiredBinId` across
198
+ empty bins only — also always uses the max traversal window, no count parameter.
199
+
200
+ #### Transfer hooks
165
201
 
166
- If either mint carries an active Token-2022 `TransferHook` extension, `swapExactIn()`/`swapExactOut()` (and every position method below) resolve and append its extra accounts automatically — nothing to configure. `Pool.resolveTransferHookAccountsX(transferAccounts)`/`resolveTransferHookAccountsY(transferAccounts)` are exposed publicly if you need to resolve them yourself for a custom instruction.
202
+ If either mint carries an active Token-2022 `TransferHook` extension, `swapExactIn()`/
203
+ `swapExactOut()` (and every position method above) resolve and append its extra accounts
204
+ automatically — nothing to configure. `Pool.resolveTransferHookAccountsX(transferAccounts)`/
205
+ `resolveTransferHookAccountsY(transferAccounts)` are exposed publicly if you need to resolve
206
+ them yourself for a custom instruction.
207
+
208
+ #### Looking up positions
167
209
 
168
210
  Refresh a position's cached state after it changes on-chain (e.g. after a deposit lands):
169
211
 
@@ -171,7 +213,8 @@ Refresh a position's cached state after it changes on-chain (e.g. after a deposi
171
213
  await position.refresh();
172
214
  ```
173
215
 
174
- Look up several positions at once, e.g. every position minted to a given owner across all their pools:
216
+ Look up several positions at once, e.g. every position minted to a given owner across all
217
+ their pools:
175
218
 
176
219
  ```ts
177
220
  // Map<poolAddress, positionMintAddress[]>
@@ -190,7 +233,16 @@ Or fetch a single position directly if you already know its address:
190
233
  const positionByAddress = await pool.getPosition(positionAddress);
191
234
  ```
192
235
 
193
- Claim fees across many positions at once with `Position.claimAllFees()` — it skips positions with nothing pending (checked locally, no extra RPC) and batches the rest into `DEFAULT_POSITIONS_PER_CLAIM`-sized (overridable via a third argument) instruction groups, one per transaction, sharing a single set of ATA setup/teardown instructions across the whole batch rather than repeating them per position. All positions must belong to the same pool:
236
+ #### Claiming across positions
237
+
238
+ Claim fees across many positions at once with `Position.claimAllFees()`:
239
+
240
+ - Skips positions with nothing pending (checked locally, no extra RPC).
241
+ - Batches the rest into `DEFAULT_POSITIONS_PER_CLAIM`-sized (overridable via a third argument)
242
+ instruction groups, one per transaction.
243
+ - Shares a single set of ATA setup/teardown instructions across the whole batch, rather than
244
+ repeating them per position.
245
+ - Requires all positions to belong to the same pool.
194
246
 
195
247
  ```ts
196
248
  const positions = await pool.getAllPositionsByPositionMints(positionMints);
@@ -203,7 +255,12 @@ for (const claimIxs of claimTxs) {
203
255
 
204
256
  ### Price math
205
257
 
206
- `getBaseBinPrice(binStep)`, `getBinPrice(baseBinPrice, binId)`, and `getBinPriceFromStep(binStep, binId)` are direct `bigint` ports of the on-chain Q64.64 price math (`bin_math.rs`'s `base_bin_price`/`bin_price`/`bin_price_from_step`) — useful for computing a bin's price without an RPC round trip, e.g. when picking `lowerBinId`/`upperBinId` for a new position before it exists on-chain. `getBinPrice`/`getBinPriceFromStep` return `undefined` (mirroring the Rust `Option`) if `binId` is outside the representable range for that `binStep`:
258
+ `getBaseBinPrice(binStep)`, `getBinPrice(baseBinPrice, binId)`, and
259
+ `getBinPriceFromStep(binStep, binId)` are direct `bigint` ports of the on-chain Q64.64 price
260
+ math. They're useful for computing a bin's price without an RPC round trip — e.g. when picking
261
+ `lowerBinId`/`upperBinId` for a new position before it exists on-chain. `getBinPrice`/
262
+ `getBinPriceFromStep` return `undefined` if `binId` is outside the representable range for that
263
+ `binStep`:
207
264
 
208
265
  ```ts
209
266
  import { getBinPriceFromStep } from "@picon-finance/dlmm-sdk";
@@ -213,19 +270,24 @@ const rawPrice = getBinPriceFromStep(pool.data.binStep, pool.activeBinId); // Q6
213
270
 
214
271
  ### Events
215
272
 
216
- Event decoding and subscriptions are a separate, opt-in feature under the `events` namespace — independent of `DlmmProgram`/`Pool`/`Position`/`BinArray`:
273
+ Event decoding and subscriptions are a separate, opt-in feature under the `events` namespace —
274
+ independent of `DlmmProgram`/`Pool`/`Position`/`BinArray`:
217
275
 
218
276
  ```ts
219
277
  const rpcSubscriptions = createSolanaRpcSubscriptions("wss://api.mainnet-beta.solana.com");
220
278
 
279
+ // Omit programAddress to target mainnet, same as DlmmProgram above. Testing against devnet
280
+ // instead? Import DEVNET_PROGRAM_ADDRESS and pass it as { programAddress: DEVNET_PROGRAM_ADDRESS }.
221
281
  const unsubscribe = await events.onEvent(rpcSubscriptions, (event) => {
222
282
  console.log(event.name, event.data);
223
- }, { programAddress: DEVNET_PROGRAM_ADDRESS });
283
+ });
224
284
 
225
285
  // unsubscribe() when done.
226
286
  ```
227
287
 
228
- `MAINNET_PROGRAM_ADDRESS` and `DEVNET_PROGRAM_ADDRESS` are both exported for convenience; omitting `programAddress` defaults to mainnet.
288
+ `MAINNET_PROGRAM_ADDRESS` and `DEVNET_PROGRAM_ADDRESS` are both exported for convenience.
289
+ Everywhere above that takes a `programAddress`, omitting it defaults to mainnet — pass
290
+ `DEVNET_PROGRAM_ADDRESS` explicitly to point the same code at devnet instead.
229
291
 
230
292
  ## License
231
293
 
@@ -4,7 +4,7 @@
4
4
  "name": "picon_dlmm",
5
5
  "version": "1.1.2",
6
6
  "spec": "0.1.0",
7
- "description": "Created with Anchor"
7
+ "description": "Picon DLMM program"
8
8
  },
9
9
  "instructions": [
10
10
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picon-finance/dlmm-sdk",
3
- "version": "1.18.2",
3
+ "version": "1.18.3",
4
4
  "description": "Typescript SDK for interacting with the Picon DLMM protocol",
5
5
  "author": "Picon Finance",
6
6
  "license": "MIT",
@@ -46,9 +46,9 @@
46
46
  "@solana-program/system": "^0.13.0",
47
47
  "@solana-program/token": "^0.15.0",
48
48
  "@solana-program/token-2022": "^0.15.0",
49
- "@solana/kit": "^7.1.0",
50
- "@solana/program-client-core": "^7.1.0",
51
- "@solana/transaction-messages": "^7.1.0"
49
+ "@solana/kit": "^7.1.1",
50
+ "@solana/program-client-core": "^7.1.1",
51
+ "@solana/transaction-messages": "^7.1.1"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/bun": "latest",
@@ -4,7 +4,7 @@
4
4
  "name": "picon_dlmm",
5
5
  "version": "1.1.2",
6
6
  "spec": "0.1.0",
7
- "description": "Created with Anchor"
7
+ "description": "Picon DLMM program"
8
8
  },
9
9
  "instructions": [
10
10
  {