@meteora-ag/dynamic-bonding-curve-sdk 1.0.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/src/types.ts ADDED
@@ -0,0 +1,465 @@
1
+ import type {
2
+ Accounts,
3
+ BN,
4
+ IdlAccounts,
5
+ IdlTypes,
6
+ Program,
7
+ } from '@coral-xyz/anchor'
8
+ import type { DynamicBondingCurve } from './idl/dynamic-bonding-curve/idl'
9
+ import type { Keypair, PublicKey, Transaction } from '@solana/web3.js'
10
+ import Decimal from 'decimal.js'
11
+
12
+ // Program Type
13
+ export type DynamicBondingCurveProgram = Program<DynamicBondingCurve>
14
+
15
+ /////////////////
16
+ // IX ACCOUNTS //
17
+ /////////////////
18
+
19
+ export type ClaimProtocolFeeAccounts = Accounts<
20
+ DynamicBondingCurve['instructions']['0']
21
+ >['claimProtocolFee']
22
+
23
+ export type ClaimTradingFeeAccounts = Accounts<
24
+ DynamicBondingCurve['instructions']['1']
25
+ >['claimTradingFee']
26
+
27
+ export type CloseClaimFeeOperatorAccounts = Accounts<
28
+ DynamicBondingCurve['instructions']['2']
29
+ >['closeClaimFeeOperator']
30
+
31
+ export type CreateClaimFeeOperatorAccounts = Accounts<
32
+ DynamicBondingCurve['instructions']['3']
33
+ >['createClaimFeeOperator']
34
+
35
+ export type CreateConfigAccounts = Accounts<
36
+ DynamicBondingCurve['instructions']['4']
37
+ >['createConfig']
38
+
39
+ export type CreateLockerAccounts = Accounts<
40
+ DynamicBondingCurve['instructions']['5']
41
+ >['createLocker']
42
+
43
+ export type CreatePartnerMetadata = Accounts<
44
+ DynamicBondingCurve['instructions']['6']
45
+ >['createPartnerMetadata']
46
+
47
+ export type CreateVirtualPoolMetadata = Accounts<
48
+ DynamicBondingCurve['instructions']['7']
49
+ >['createVirtualPoolMetadata']
50
+
51
+ export type InitializeVirtualPoolWithSplTokenAccounts = Accounts<
52
+ DynamicBondingCurve['instructions']['8']
53
+ >['initializeVirtualPoolWithSplToken']
54
+
55
+ export type InitializeVirtualPoolWithToken2022Accounts = Accounts<
56
+ DynamicBondingCurve['instructions']['9']
57
+ >['initializeVirtualPoolWithToken2022']
58
+
59
+ export type MigrateMeteoraDammAccounts = Accounts<
60
+ DynamicBondingCurve['instructions']['10']
61
+ >['migrateMeteoraDamm']
62
+
63
+ export type MigrateMeteoraDammClaimLpTokenAccounts = Accounts<
64
+ DynamicBondingCurve['instructions']['11']
65
+ >['migrateMeteoraDammClaimLpToken']
66
+
67
+ export type MigrateMeteoraDammLockLpTokenAccounts = Accounts<
68
+ DynamicBondingCurve['instructions']['12']
69
+ >['migrateMeteoraDammLockLpToken']
70
+
71
+ export type MigrationDammV2Accounts = Accounts<
72
+ DynamicBondingCurve['instructions']['13']
73
+ >['migrationDammV2']
74
+
75
+ export type MigrationDammV2CreateMetadataAccounts = Accounts<
76
+ DynamicBondingCurve['instructions']['14']
77
+ >['migrationDammV2CreateMetadata']
78
+
79
+ export type MigrationMeteoraDammCreateMetadataAccounts = Accounts<
80
+ DynamicBondingCurve['instructions']['15']
81
+ >['migrationMeteoraDammCreateMetadata']
82
+
83
+ export type PartnerWithdrawSurplusAccounts = Accounts<
84
+ DynamicBondingCurve['instructions']['16']
85
+ >['partnerWithdrawSurplus']
86
+
87
+ export type SwapAccounts = Accounts<
88
+ DynamicBondingCurve['instructions']['18']
89
+ >['swap']
90
+
91
+ ///////////////
92
+ // IDL Types //
93
+ ///////////////
94
+
95
+ export type ConfigParameters = IdlTypes<DynamicBondingCurve>['configParameters']
96
+ export type InitializePoolParameters =
97
+ IdlTypes<DynamicBondingCurve>['initializePoolParameters']
98
+ export type SwapParameters = IdlTypes<DynamicBondingCurve>['swapParameters']
99
+ export type PoolFeeParameters =
100
+ IdlTypes<DynamicBondingCurve>['poolFeeParameters']
101
+ export type DynamicFeeParameters =
102
+ IdlTypes<DynamicBondingCurve>['dynamicFeeParameters']
103
+ export type LiquidityDistributionParameters =
104
+ IdlTypes<DynamicBondingCurve>['liquidityDistributionParameters']
105
+ export type PoolFeesConfig = IdlTypes<DynamicBondingCurve>['poolFeesConfig']
106
+ export type DynamicFeeConfig = IdlTypes<DynamicBondingCurve>['dynamicFeeConfig']
107
+ export type BaseFeeConfig = IdlTypes<DynamicBondingCurve>['baseFeeConfig']
108
+ export type PoolFees = IdlTypes<DynamicBondingCurve>['poolFees']
109
+ export type PoolMetrics = IdlTypes<DynamicBondingCurve>['poolMetrics']
110
+ export type SwapResult = IdlTypes<DynamicBondingCurve>['swapResult']
111
+ export type CreatePartnerMetadataParameters =
112
+ IdlTypes<DynamicBondingCurve>['createPartnerMetadataParameters']
113
+ export type CreateVirtualPoolMetadataParameters =
114
+ IdlTypes<DynamicBondingCurve>['createVirtualPoolMetadataParameters']
115
+
116
+ //////////////////
117
+ // IDL ACCOUNTS //
118
+ //////////////////
119
+
120
+ export type ClaimFeeOperator =
121
+ IdlAccounts<DynamicBondingCurve>['claimFeeOperator']
122
+ export type Config = IdlAccounts<DynamicBondingCurve>['config']
123
+ export type MeteoraDammMigrationMetadata =
124
+ IdlAccounts<DynamicBondingCurve>['meteoraDammMigrationMetadata']
125
+ export type LockEscrow = IdlAccounts<DynamicBondingCurve>['lockEscrow']
126
+ export type VolatilityTracker =
127
+ IdlTypes<DynamicBondingCurve>['volatilityTracker']
128
+ export type VirtualPool = IdlAccounts<DynamicBondingCurve>['virtualPool']
129
+ export type PoolConfig = IdlAccounts<DynamicBondingCurve>['poolConfig']
130
+ export type PartnerMetadata =
131
+ IdlAccounts<DynamicBondingCurve>['partnerMetadata']
132
+ export type VirtualPoolMetadata =
133
+ IdlAccounts<DynamicBondingCurve>['virtualPoolMetadata']
134
+
135
+ ///////////
136
+ // ENUMS //
137
+ ///////////
138
+
139
+ export enum ActivationType {
140
+ Slot = 0,
141
+ Timestamp = 1,
142
+ }
143
+
144
+ export enum TokenType {
145
+ SPL = 0,
146
+ Token2022 = 1,
147
+ }
148
+
149
+ export enum CollectFeeMode {
150
+ OnlyQuote = 0,
151
+ Both = 1,
152
+ }
153
+
154
+ export enum MigrationOption {
155
+ MET_DAMM = 0,
156
+ MET_DAMM_V2 = 1,
157
+ }
158
+
159
+ export enum CollectFeeMode {
160
+ QuoteToken = 0,
161
+ OutputToken = 1,
162
+ }
163
+
164
+ export enum FeeSchedulerMode {
165
+ Linear = 0,
166
+ Exponential = 1,
167
+ }
168
+
169
+ export enum MigrationFeeOption {
170
+ FixedBps25 = 0,
171
+ FixedBps30 = 1,
172
+ FixedBps100 = 2,
173
+ FixedBps200 = 3,
174
+ }
175
+
176
+ export enum TokenDecimal {
177
+ SIX = 6,
178
+ NINE = 9,
179
+ }
180
+
181
+ export enum TradeDirection {
182
+ BaseToQuote = 0,
183
+ QuoteToBase = 1,
184
+ }
185
+
186
+ export enum Rounding {
187
+ Up,
188
+ Down,
189
+ }
190
+
191
+ ///////////
192
+ // TYPES //
193
+ ///////////
194
+
195
+ export type CreateConfigParam = Omit<
196
+ CreateConfigAccounts,
197
+ 'program' | 'eventAuthority' | 'systemProgram'
198
+ > &
199
+ ConfigParameters
200
+
201
+ export type CreateDammMigrationMetadataParam = {
202
+ payer: PublicKey
203
+ virtualPool: PublicKey
204
+ config: PublicKey
205
+ migrateToDammV2: boolean
206
+ }
207
+
208
+ export type CreateConstantProductConfigWithLockVestingParam = {
209
+ lockVestingParams: {
210
+ percentageSupplyVesting: number
211
+ frequency: number
212
+ numberOfPeriod: number
213
+ cliffUnlockEnabled: boolean
214
+ }
215
+ totalTokenSupply: number
216
+ percentageSupplyOnMigration: number
217
+ startPrice: Decimal
218
+ migrationPrice: Decimal
219
+ tokenBaseDecimal: number
220
+ tokenQuoteDecimal: number
221
+ swapBufferPercentage: number
222
+ baseFeeBps: number
223
+ dynamicFeeEnabled: boolean
224
+ activationType: ActivationType
225
+ collectFeeMode: CollectFeeMode
226
+ migrationOption: MigrationOption
227
+ migrationFeeOption: MigrationFeeOption
228
+ tokenType: TokenType
229
+ partnerLpPercentage: number
230
+ creatorLpPercentage: number
231
+ partnerLockedLpPercentage: number
232
+ creatorLockedLpPercentage: number
233
+ feeClaimer: PublicKey
234
+ leftoverReceiver: PublicKey
235
+ payer: PublicKey
236
+ quoteMint: PublicKey
237
+ config: PublicKey
238
+ }
239
+
240
+ export type CreateConstantProductConfigWithoutLockVestingParam = {
241
+ totalTokenSupply: number
242
+ percentageSupplyOnMigration: number
243
+ startPrice: Decimal
244
+ tokenBaseDecimal: number
245
+ tokenQuoteDecimal: number
246
+ swapBufferPercentage: number
247
+ baseFeeBps: number
248
+ dynamicFeeEnabled: boolean
249
+ activationType: ActivationType
250
+ collectFeeMode: CollectFeeMode
251
+ migrationOption: MigrationOption
252
+ migrationFeeOption: MigrationFeeOption
253
+ tokenType: TokenType
254
+ partnerLpPercentage: number
255
+ creatorLpPercentage: number
256
+ partnerLockedLpPercentage: number
257
+ creatorLockedLpPercentage: number
258
+ feeClaimer: PublicKey
259
+ leftoverReceiver: PublicKey
260
+ payer: PublicKey
261
+ quoteMint: PublicKey
262
+ config: PublicKey
263
+ }
264
+
265
+ export type DesignCurveParam = {
266
+ tokenDecimal: TokenDecimal
267
+ migrationQuoteThreshold: BN
268
+ tokenBaseSupply: BN
269
+ migrationBasePercent: number
270
+ }
271
+
272
+ export type DesignConstantProductCurveWithLockVestingParam = {
273
+ lockVestingParams: {
274
+ percentageSupplyVesting: number
275
+ frequency: number
276
+ numberOfPeriod: number
277
+ cliffUnlockEnabled: boolean
278
+ }
279
+ totalTokenSupply: number
280
+ percentageSupplyOnMigration: number
281
+ startPrice: Decimal
282
+ migrationPrice: Decimal
283
+ tokenBaseDecimal: number
284
+ tokenQuoteDecimal: number
285
+ swapBufferPercentage: number
286
+ baseFeeBps: number
287
+ dynamicFeeEnabled: boolean
288
+ activationType: ActivationType
289
+ collectFeeMode: CollectFeeMode
290
+ migrationOption: MigrationOption
291
+ migrationFeeOption: MigrationFeeOption
292
+ tokenType: TokenType
293
+ partnerLpPercentage: number
294
+ creatorLpPercentage: number
295
+ partnerLockedLpPercentage: number
296
+ creatorLockedLpPercentage: number
297
+ }
298
+
299
+ export type DesignConstantProductCurveWithoutLockVestingParam = {
300
+ totalTokenSupply: number
301
+ percentageSupplyOnMigration: number
302
+ startPrice: Decimal
303
+ tokenBaseDecimal: number
304
+ tokenQuoteDecimal: number
305
+ swapBufferPercentage: number
306
+ baseFeeBps: number
307
+ dynamicFeeEnabled: boolean
308
+ activationType: ActivationType
309
+ collectFeeMode: CollectFeeMode
310
+ migrationOption: MigrationOption
311
+ migrationFeeOption: MigrationFeeOption
312
+ tokenType: TokenType
313
+ partnerLpPercentage: number
314
+ creatorLpPercentage: number
315
+ partnerLockedLpPercentage: number
316
+ creatorLockedLpPercentage: number
317
+ }
318
+
319
+ export type DesignCurveResponse = {
320
+ sqrtStartPrice: BN
321
+ curve: LiquidityDistributionParameters[]
322
+ }
323
+
324
+ export type MigrateToDammV1Param = {
325
+ payer: PublicKey
326
+ virtualPool: PublicKey
327
+ dammConfig: PublicKey
328
+ }
329
+
330
+ export type MigrateToDammV2Param = {
331
+ payer: PublicKey
332
+ virtualPool: PublicKey
333
+ dammConfig: PublicKey
334
+ }
335
+
336
+ export type MigrateToDammV2Response = {
337
+ transaction: Transaction
338
+ firstPositionNftKeypair: Keypair
339
+ secondPositionNftKeypair: Keypair
340
+ }
341
+
342
+ export type ClaimTradingFeeParam = {
343
+ feeClaimer: PublicKey
344
+ pool: PublicKey
345
+ maxBaseAmount: BN
346
+ maxQuoteAmount: BN
347
+ }
348
+
349
+ export type CreateVirtualPoolMetadataParam = {
350
+ virtualPool: PublicKey
351
+ name: string
352
+ website: string
353
+ logo: string
354
+ creator: PublicKey
355
+ payer: PublicKey
356
+ }
357
+
358
+ export type CreatePartnerMetadataParam = {
359
+ name: string
360
+ website: string
361
+ logo: string
362
+ feeClaimer: PublicKey
363
+ payer: PublicKey
364
+ }
365
+
366
+ export type CreatePoolParam = {
367
+ name: string
368
+ symbol: string
369
+ uri: string
370
+ config: PublicKey
371
+ creator: PublicKey
372
+ baseMint: PublicKey
373
+ quoteMint: PublicKey
374
+ baseTokenType: TokenType
375
+ quoteTokenType: TokenType
376
+ }
377
+
378
+ export type SwapParam = {
379
+ owner: PublicKey
380
+ amountIn: BN
381
+ minimumAmountOut: BN
382
+ swapBaseForQuote: boolean
383
+ }
384
+
385
+ export type SwapQuoteParam = {
386
+ virtualPool: VirtualPool
387
+ config: PoolConfig
388
+ swapBaseForQuote: boolean
389
+ amountIn: BN
390
+ hasReferral: boolean
391
+ currentPoint: BN
392
+ }
393
+
394
+ export type DammLpTokenParam = {
395
+ payer: PublicKey
396
+ virtualPool: PublicKey
397
+ dammConfig: PublicKey
398
+ isPartner: boolean
399
+ }
400
+
401
+ export type PartnerWithdrawSurplusParam = {
402
+ feeClaimer: PublicKey
403
+ virtualPool: PublicKey
404
+ }
405
+
406
+ export type WithdrawLeftoverParam = {
407
+ payer: PublicKey
408
+ virtualPool: PublicKey
409
+ }
410
+
411
+ export type CreateLockerParam = {
412
+ payer: PublicKey
413
+ virtualPool: PublicKey
414
+ }
415
+
416
+ ////////////////
417
+ // INTERFACES //
418
+ ////////////////
419
+
420
+ export interface FeeResult {
421
+ amount: BN
422
+ protocolFee: BN
423
+ tradingFee: BN
424
+ referralFee: BN
425
+ }
426
+
427
+ export interface FeeMode {
428
+ feesOnInput: boolean
429
+ feesOnBaseToken: boolean
430
+ hasReferral: boolean
431
+ }
432
+
433
+ export interface QuoteResult {
434
+ amountOut: BN
435
+ minimumAmountOut: BN
436
+ nextSqrtPrice: BN
437
+ fee: {
438
+ trading: BN
439
+ protocol: BN
440
+ referral?: BN
441
+ }
442
+ price: {
443
+ beforeSwap: number
444
+ afterSwap: number
445
+ }
446
+ }
447
+
448
+ export interface FeeOnAmountResult {
449
+ amount: BN // Amount remaining after taking trading fee
450
+ protocolFee: BN // Final protocol fee (after referral deduction)
451
+ tradingFee: BN // Portion of trading fee NOT going to protocol
452
+ referralFee: BN // Referral fee amount
453
+ }
454
+
455
+ export interface PrepareSwapParams {
456
+ inputMint: PublicKey
457
+ outputMint: PublicKey
458
+ inputTokenProgram: PublicKey
459
+ outputTokenProgram: PublicKey
460
+ }
461
+
462
+ export interface SwapAmount {
463
+ outputAmount: BN
464
+ nextSqrtPrice: BN
465
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,252 @@
1
+ import { AnchorProvider, Program, Wallet } from '@coral-xyz/anchor'
2
+ import { TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'
3
+ import {
4
+ PublicKey,
5
+ SystemProgram,
6
+ TransactionInstruction,
7
+ type Connection,
8
+ type GetProgramAccountsFilter,
9
+ } from '@solana/web3.js'
10
+ import type { DynamicBondingCurve } from './idl/dynamic-bonding-curve/idl'
11
+ import DynamicBondingCurveIDL from './idl/dynamic-bonding-curve/idl.json'
12
+ import type { DynamicVault } from './idl/dynamic-vault/idl'
13
+ import DynamicVaultIDL from './idl/dynamic-vault/idl.json'
14
+ import type { DammV1 } from './idl/damm-v1/idl'
15
+ import DammV1IDL from './idl/damm-v1/idl.json'
16
+ import {
17
+ ASSOCIATED_TOKEN_PROGRAM_ID,
18
+ createCloseAccountInstruction,
19
+ getAssociatedTokenAddressSync,
20
+ NATIVE_MINT,
21
+ TOKEN_PROGRAM_ID,
22
+ } from '@solana/spl-token'
23
+ import { TokenType } from './types'
24
+ import BN from 'bn.js'
25
+
26
+ export function getSecondKey(key1: PublicKey, key2: PublicKey) {
27
+ const buf1 = key1.toBuffer()
28
+ const buf2 = key2.toBuffer()
29
+ // Buf1 > buf2
30
+ if (Buffer.compare(buf1, buf2) === 1) {
31
+ return buf2
32
+ }
33
+ return buf1
34
+ }
35
+
36
+ export function getFirstKey(key1: PublicKey, key2: PublicKey) {
37
+ const buf1 = key1.toBuffer()
38
+ const buf2 = key2.toBuffer()
39
+ // Buf1 > buf2
40
+ if (Buffer.compare(buf1, buf2) === 1) {
41
+ return buf1
42
+ }
43
+ return buf2
44
+ }
45
+
46
+ /**
47
+ * Create a program instance
48
+ * @param connection - The connection to the network
49
+ * @returns The program instance
50
+ */
51
+ export function createProgram(connection: Connection) {
52
+ const provider = new AnchorProvider(connection, null as unknown as Wallet, {
53
+ commitment: 'confirmed',
54
+ })
55
+ const program = new Program<DynamicBondingCurve>(
56
+ DynamicBondingCurveIDL,
57
+ provider
58
+ )
59
+
60
+ return { program }
61
+ }
62
+
63
+ /**
64
+ * Create a vault program instance
65
+ * @param connection - The connection to the network
66
+ * @returns The vault program instance
67
+ */
68
+ export function createVaultProgram(
69
+ connection: Connection
70
+ ): Program<DynamicVault> {
71
+ const provider = new AnchorProvider(connection, null as unknown as Wallet, {
72
+ commitment: 'confirmed',
73
+ })
74
+
75
+ const program = new Program<DynamicVault>(DynamicVaultIDL, provider)
76
+ return program
77
+ }
78
+
79
+ /**
80
+ * Create a DAMM V1 program instance
81
+ * @param connection - The connection to the network
82
+ * @returns The DAMM V1 program instance
83
+ */
84
+ export function createDammV1Program(connection: Connection): Program<DammV1> {
85
+ const provider = new AnchorProvider(connection, null as unknown as Wallet, {
86
+ commitment: 'confirmed',
87
+ })
88
+
89
+ const program = new Program<DammV1>(DammV1IDL, provider)
90
+ return program
91
+ }
92
+
93
+ /**
94
+ * Find the associated token address for a wallet and token mint
95
+ * @param walletAddress - The wallet address
96
+ * @param tokenMintAddress - The token mint address
97
+ * @param tokenProgramId - The token program ID
98
+ * @returns The associated token address
99
+ */
100
+ export function findAssociatedTokenAddress(
101
+ walletAddress: PublicKey,
102
+ tokenMintAddress: PublicKey,
103
+ tokenProgramId: PublicKey
104
+ ): PublicKey {
105
+ return PublicKey.findProgramAddressSync(
106
+ [
107
+ walletAddress.toBuffer(),
108
+ tokenProgramId.toBuffer(),
109
+ tokenMintAddress.toBuffer(),
110
+ ],
111
+ ASSOCIATED_TOKEN_PROGRAM_ID
112
+ )[0]
113
+ }
114
+
115
+ /**
116
+ * Create a wrap SOL instruction
117
+ * @param from - The from address
118
+ * @param to - The to address
119
+ * @param amount - The amount to wrap
120
+ * @returns The wrap SOL instruction
121
+ */
122
+ export function wrapSOLInstruction(
123
+ from: PublicKey,
124
+ to: PublicKey,
125
+ amount: bigint
126
+ ): TransactionInstruction[] {
127
+ return [
128
+ SystemProgram.transfer({
129
+ fromPubkey: from,
130
+ toPubkey: to,
131
+ lamports: amount,
132
+ }),
133
+ new TransactionInstruction({
134
+ keys: [
135
+ {
136
+ pubkey: to,
137
+ isSigner: false,
138
+ isWritable: true,
139
+ },
140
+ ],
141
+ data: Buffer.from(new Uint8Array([17])),
142
+ programId: TOKEN_PROGRAM_ID,
143
+ }),
144
+ ]
145
+ }
146
+
147
+ /**
148
+ * Create an unwrap SOL instruction
149
+ * @param owner - The owner of the SOL
150
+ * @param allowOwnerOffCurve - Whether to allow the owner to be off curve
151
+ * @returns The unwrap SOL instruction
152
+ */
153
+ export function unwrapSOLInstruction(
154
+ owner: PublicKey,
155
+ allowOwnerOffCurve = true
156
+ ): TransactionInstruction | null {
157
+ const wSolATAAccount = getAssociatedTokenAddressSync(
158
+ NATIVE_MINT,
159
+ owner,
160
+ allowOwnerOffCurve
161
+ )
162
+ if (wSolATAAccount) {
163
+ const closedWrappedSolInstruction = createCloseAccountInstruction(
164
+ wSolATAAccount,
165
+ owner,
166
+ owner,
167
+ [],
168
+ TOKEN_PROGRAM_ID
169
+ )
170
+ return closedWrappedSolInstruction
171
+ }
172
+ return null
173
+ }
174
+
175
+ /**
176
+ * Get the token program for a given token type
177
+ * @param tokenType - The token type
178
+ * @returns The token program
179
+ */
180
+ export function getTokenProgram(tokenType: TokenType): PublicKey {
181
+ return tokenType === TokenType.SPL
182
+ ? TOKEN_PROGRAM_ID
183
+ : TOKEN_2022_PROGRAM_ID
184
+ }
185
+
186
+ /**
187
+ * Create a memcmp filter for owner-based filtering
188
+ * @param owner - The owner public key or string
189
+ * @param offset - The offset where the owner field is located in the account data
190
+ * @returns A GetProgramAccountsFilter array with the owner filter
191
+ */
192
+ export function createProgramAccountFilter(
193
+ owner: PublicKey | string,
194
+ offset: number
195
+ ): GetProgramAccountsFilter[] {
196
+ const ownerKey = typeof owner === 'string' ? new PublicKey(owner) : owner
197
+ return [
198
+ {
199
+ memcmp: {
200
+ offset,
201
+ bytes: ownerKey.toBase58(),
202
+ encoding: 'base58',
203
+ },
204
+ },
205
+ ]
206
+ }
207
+
208
+ /**
209
+ * Generic account fetch helper
210
+ * @param accountAddress - The address of the account to fetch
211
+ * @param accountType - The type of account to fetch from program.account
212
+ * @returns The fetched account data
213
+ */
214
+ export async function getAccountData<T>(
215
+ accountAddress: PublicKey | string,
216
+ accountType: keyof Program<DynamicBondingCurve>['account'],
217
+ program: Program<DynamicBondingCurve>
218
+ ): Promise<T> {
219
+ const address =
220
+ accountAddress instanceof PublicKey
221
+ ? accountAddress
222
+ : new PublicKey(accountAddress)
223
+
224
+ return (await program.account[accountType].fetchNullable(address)) as T
225
+ }
226
+
227
+ /**
228
+ * Check if a mint is the native SOL mint
229
+ * @param mint - The mint to check
230
+ * @returns Whether the mint is the native SOL mint
231
+ */
232
+ export function isNativeSol(mint: PublicKey): boolean {
233
+ return mint.toString() === NATIVE_MINT.toString()
234
+ }
235
+
236
+ // Helper function to convert BN values to decimal strings
237
+ export function convertBNToDecimal<T>(obj: T): T {
238
+ if (obj instanceof BN) {
239
+ return obj.toString(10) as T
240
+ }
241
+ if (Array.isArray(obj)) {
242
+ return obj.map((item) => convertBNToDecimal(item)) as T
243
+ }
244
+ if (obj && typeof obj === 'object') {
245
+ const result = {} as T
246
+ for (const key in obj) {
247
+ result[key] = convertBNToDecimal(obj[key])
248
+ }
249
+ return result
250
+ }
251
+ return obj
252
+ }