@send-fun/sdk 1.1.0 → 2.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.
Files changed (80) hide show
  1. package/README.md +8 -9
  2. package/dist/index.cjs +777 -433
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +678 -217
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.mts +678 -217
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.mjs +777 -433
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +7 -7
  11. package/src/dex/generated/accounts/globalConfig.ts +39 -2
  12. package/src/dex/generated/accounts/pool.ts +60 -9
  13. package/src/dex/generated/accounts/rewardAccrual.ts +39 -2
  14. package/src/dex/generated/errors/sendDex.ts +16 -8
  15. package/src/dex/generated/events/creatorClaimEvent.ts +3 -2
  16. package/src/dex/generated/events/poolCreateEvent.ts +8 -2
  17. package/src/dex/generated/events/tokenCreateEvent.ts +8 -9
  18. package/src/dex/generated/events/tradeEvent.ts +9 -2
  19. package/src/dex/generated/index.ts +1 -0
  20. package/src/dex/generated/instructions/claimCreatorFees.ts +21 -5
  21. package/src/{nexus → dex}/generated/pdas/creatorFeeConfig.ts +6 -6
  22. package/src/dex/generated/pdas/index.ts +1 -0
  23. package/src/dex/generated/plugins/sendDex.ts +3 -0
  24. package/src/dex/generated/shared/index.ts +52 -0
  25. package/src/dex/trade.ts +12 -13
  26. package/src/launchpad/create.ts +13 -38
  27. package/src/launchpad/generated/accounts/bondingCurve.ts +62 -9
  28. package/src/launchpad/generated/accounts/globalConfig.ts +39 -2
  29. package/src/launchpad/generated/accounts/rewardAccrual.ts +39 -2
  30. package/src/launchpad/generated/errors/sendLaunchpad.ts +12 -4
  31. package/src/launchpad/generated/events/completeEvent.ts +3 -2
  32. package/src/launchpad/generated/events/creatorClaimEvent.ts +3 -2
  33. package/src/launchpad/generated/events/migrateEvent.ts +3 -2
  34. package/src/launchpad/generated/events/tokenCreateEvent.ts +10 -9
  35. package/src/launchpad/generated/events/tradeEvent.ts +9 -2
  36. package/src/launchpad/generated/index.ts +1 -0
  37. package/src/launchpad/generated/instructions/claimCreatorFees.ts +17 -4
  38. package/src/launchpad/generated/instructions/createToken.ts +32 -50
  39. package/src/launchpad/generated/instructions/migrate.ts +79 -12
  40. package/src/launchpad/generated/pdas/creatorFeeConfig.ts +39 -0
  41. package/src/launchpad/generated/pdas/index.ts +1 -0
  42. package/src/launchpad/generated/plugins/sendLaunchpad.ts +3 -0
  43. package/src/launchpad/generated/shared/index.ts +52 -0
  44. package/src/launchpad/migrate.ts +7 -4
  45. package/src/launchpad/trade.ts +15 -15
  46. package/src/math/amm.ts +40 -33
  47. package/src/math/fee-decay.ts +3 -2
  48. package/src/math/fees.ts +4 -2
  49. package/src/math/internal.ts +1 -1
  50. package/src/nexus/fee-helpers.ts +10 -5
  51. package/src/nexus/generated/accounts/altRegistry.ts +41 -2
  52. package/src/nexus/generated/accounts/feePreset.ts +43 -4
  53. package/src/nexus/generated/accounts/globalConfig.ts +39 -2
  54. package/src/nexus/generated/accounts/index.ts +0 -1
  55. package/src/nexus/generated/accounts/partnerConfig.ts +48 -5
  56. package/src/nexus/generated/accounts/partnerMetadata.ts +39 -2
  57. package/src/nexus/generated/accounts/rewardState.ts +41 -2
  58. package/src/nexus/generated/accounts/sendNexus.accounts.ts +0 -5
  59. package/src/nexus/generated/accounts/stakingConfig.ts +39 -2
  60. package/src/nexus/generated/accounts/userRewardDebt.ts +42 -5
  61. package/src/nexus/generated/accounts/userStakePosition.ts +42 -5
  62. package/src/nexus/generated/errors/sendNexus.ts +12 -4
  63. package/src/nexus/generated/index.ts +1 -0
  64. package/src/nexus/generated/pdas/index.ts +0 -1
  65. package/src/nexus/generated/plugins/sendNexus.ts +0 -35
  66. package/src/nexus/generated/shared/index.ts +52 -0
  67. package/src/nexus/generated/types/dexFees.ts +4 -4
  68. package/src/nexus/generated/types/index.ts +0 -1
  69. package/src/nexus/generated/types/launchpadFees.ts +4 -4
  70. package/src/nexus/staking.ts +45 -41
  71. package/src/platform.ts +2 -2
  72. package/src/transfer-fee.ts +19 -17
  73. package/src/utils/chunk.ts +1 -1
  74. package/src/utils/index.ts +2 -5
  75. package/src/utils/mint-info.ts +8 -7
  76. package/src/utils/partner.ts +1 -1
  77. package/src/utils/pda.ts +1 -1
  78. package/src/nexus/generated/accounts/creatorFeeConfig.ts +0 -200
  79. package/src/nexus/generated/types/callerType.ts +0 -38
  80. package/src/utils/creator-hash.ts +0 -57
@@ -42,7 +42,11 @@ import {
42
42
  getAddressFromResolvedInstructionAccount,
43
43
  type ResolvedInstructionAccount,
44
44
  } from '@solana/kit/program-client-core';
45
- import { EVENT_AUTHORITY_PDA_ADDRESS, findPoolPda } from '../pdas/index.js';
45
+ import {
46
+ EVENT_AUTHORITY_PDA_ADDRESS,
47
+ findCreatorFeeConfigPda,
48
+ findPoolPda,
49
+ } from '../pdas/index.js';
46
50
  import { SEND_DEX_PROGRAM_ADDRESS } from '../programs/index.js';
47
51
 
48
52
  export const CLAIM_CREATOR_FEES_DISCRIMINATOR: ReadonlyUint8Array =
@@ -93,7 +97,7 @@ export type ClaimCreatorFeesInstruction<
93
97
  ? WritableAccount<TAccountPool>
94
98
  : TAccountPool,
95
99
  TAccountCreatorFeeConfig extends string
96
- ? ReadonlyAccount<TAccountCreatorFeeConfig>
100
+ ? WritableAccount<TAccountCreatorFeeConfig>
97
101
  : TAccountCreatorFeeConfig,
98
102
  TAccountNexusGlobalConfig extends string
99
103
  ? ReadonlyAccount<TAccountNexusGlobalConfig>
@@ -181,7 +185,7 @@ export type ClaimCreatorFeesAsyncInput<
181
185
  claimer: TransactionSigner<TAccountClaimer>;
182
186
  payer: TransactionSigner<TAccountPayer>;
183
187
  pool?: Address<TAccountPool>;
184
- creatorFeeConfig: Address<TAccountCreatorFeeConfig>;
188
+ creatorFeeConfig?: Address<TAccountCreatorFeeConfig>;
185
189
  baseMint: Address<TAccountBaseMint>;
186
190
  quoteMint: Address<TAccountQuoteMint>;
187
191
  quoteVault?: Address<TAccountQuoteVault>;
@@ -244,7 +248,7 @@ export async function getClaimCreatorFeesInstructionAsync<
244
248
  pool: { value: input.pool ?? null, isWritable: true },
245
249
  creatorFeeConfig: {
246
250
  value: input.creatorFeeConfig ?? null,
247
- isWritable: false,
251
+ isWritable: true,
248
252
  },
249
253
  nexusGlobalConfig: { value: null, isWritable: false },
250
254
  baseMint: { value: input.baseMint ?? null, isWritable: false },
@@ -282,6 +286,18 @@ export async function getClaimCreatorFeesInstructionAsync<
282
286
  ),
283
287
  });
284
288
  }
289
+ if (!accounts.creatorFeeConfig.value) {
290
+ accounts.creatorFeeConfig.value = await findCreatorFeeConfigPda({
291
+ baseMint: getAddressFromResolvedInstructionAccount(
292
+ 'baseMint',
293
+ accounts.baseMint.value,
294
+ ),
295
+ quoteMint: getAddressFromResolvedInstructionAccount(
296
+ 'quoteMint',
297
+ accounts.quoteMint.value,
298
+ ),
299
+ });
300
+ }
285
301
  if (!accounts.nexusGlobalConfig.value) {
286
302
  accounts.nexusGlobalConfig.value =
287
303
  '3bycfBeRULfXYqcg3DmiYFBjv6mMVidMuqKdFZJTGdNr' as Address<'3bycfBeRULfXYqcg3DmiYFBjv6mMVidMuqKdFZJTGdNr'>;
@@ -474,7 +490,7 @@ export function getClaimCreatorFeesInstruction<
474
490
  pool: { value: input.pool ?? null, isWritable: true },
475
491
  creatorFeeConfig: {
476
492
  value: input.creatorFeeConfig ?? null,
477
- isWritable: false,
493
+ isWritable: true,
478
494
  },
479
495
  nexusGlobalConfig: { value: null, isWritable: false },
480
496
  baseMint: { value: input.baseMint ?? null, isWritable: false },
@@ -13,10 +13,10 @@ import {
13
13
  type Address,
14
14
  type ProgramDerivedAddress,
15
15
  } from '@solana/kit';
16
- import { SEND_NEXUS_PROGRAM_ADDRESS } from '../programs/index.js';
16
+ import { SEND_DEX_PROGRAM_ADDRESS } from '../programs/index.js';
17
17
 
18
18
  export type CreatorFeeConfigSeeds = {
19
- creatorHash: Address;
19
+ baseMint: Address;
20
20
  quoteMint: Address;
21
21
  };
22
22
 
@@ -24,15 +24,15 @@ export async function findCreatorFeeConfigPda(
24
24
  seeds: CreatorFeeConfigSeeds,
25
25
  ): Promise<ProgramDerivedAddress> {
26
26
  return await getProgramDerivedAddress({
27
- programAddress: SEND_NEXUS_PROGRAM_ADDRESS,
27
+ programAddress: SEND_DEX_PROGRAM_ADDRESS,
28
28
  seeds: [
29
29
  getBytesEncoder().encode(
30
30
  new Uint8Array([
31
- 99, 114, 101, 97, 116, 111, 114, 95, 102, 101, 101, 95, 98,
32
- 97, 108, 97, 110, 99, 101,
31
+ 99, 114, 101, 97, 116, 111, 114, 95, 102, 101, 101, 95, 99,
32
+ 111, 110, 102, 105, 103,
33
33
  ]),
34
34
  ),
35
- getAddressEncoder().encode(seeds.creatorHash),
35
+ getAddressEncoder().encode(seeds.baseMint),
36
36
  getAddressEncoder().encode(seeds.quoteMint),
37
37
  ],
38
38
  });
@@ -6,6 +6,7 @@
6
6
  * @see https://github.com/codama-idl/codama
7
7
  */
8
8
 
9
+ export * from './creatorFeeConfig.js';
9
10
  export * from './eventAuthority.js';
10
11
  export * from './globalConfig.js';
11
12
  export * from './lpMint.js';
@@ -70,6 +70,7 @@ import {
70
70
  type SellExactOutAsyncInput,
71
71
  } from '../instructions/index.js';
72
72
  import {
73
+ findCreatorFeeConfigPda,
73
74
  findEventAuthorityPda,
74
75
  findGlobalConfigPda,
75
76
  findLpMintPda,
@@ -135,6 +136,7 @@ export type SendDexPluginInstructions = {
135
136
  export type SendDexPluginPdas = {
136
137
  pool: typeof findPoolPda;
137
138
  eventAuthority: typeof findEventAuthorityPda;
139
+ creatorFeeConfig: typeof findCreatorFeeConfigPda;
138
140
  rewardAccrual: typeof findRewardAccrualPda;
139
141
  globalConfig: typeof findGlobalConfigPda;
140
142
  lpMint: typeof findLpMintPda;
@@ -266,6 +268,7 @@ export function sendDexProgram() {
266
268
  pdas: {
267
269
  pool: findPoolPda,
268
270
  eventAuthority: findEventAuthorityPda,
271
+ creatorFeeConfig: findCreatorFeeConfigPda,
269
272
  rewardAccrual: findRewardAccrualPda,
270
273
  globalConfig: findGlobalConfigPda,
271
274
  lpMint: findLpMintPda,
@@ -0,0 +1,52 @@
1
+ /**
2
+ * This code was AUTOGENERATED using the Codama library.
3
+ * Please DO NOT EDIT THIS FILE, instead use visitors
4
+ * to add features, then rerun Codama to update it.
5
+ *
6
+ * @see https://github.com/codama-idl/codama
7
+ */
8
+
9
+ import type { Address, EncodedAccount, MaybeEncodedAccount } from '@solana/kit';
10
+
11
+ /** The System Program, which owns every address nobody has created an account at yet. */
12
+ const SYSTEM_PROGRAM_ADDRESS =
13
+ '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>;
14
+
15
+ /**
16
+ * Whether an encoded account was created on-chain, rather than merely sent lamports.
17
+ *
18
+ * Anyone can send lamports to an address before its account is created, which leaves it on-chain,
19
+ * owned by the System Program, with no data. This returns `false` for that shape, as it does for an
20
+ * account that does not exist. Any other existing account counts as created, whoever owns it; the
21
+ * `decode*` functions still check the owner.
22
+ *
23
+ * The generated `fetchMaybe*` and `fetchAllMaybe*` helpers apply this rule themselves. Apply it to
24
+ * accounts you fetch or receive another way (subscriptions, batch loaders, caches) before passing
25
+ * them to a `decode*` function, which throws for a lamports-only account: an account passed to it as
26
+ * existing must never come back as the non-existing variant typed as an `Account`.
27
+ *
28
+ * Only a `true` result narrows the type. A lamports-only account is still `exists: true` at runtime,
29
+ * so a `false` result leaves the type unchanged instead of narrowing it to the non-existing variant.
30
+ * The `uncreated` property in the narrowed type is never present; it exists only to prevent that.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const maybeAccount = decodeMyAccount(
35
+ * accountIsCreated(encodedAccount) ? encodedAccount : { address: encodedAccount.address, exists: false },
36
+ * );
37
+ * ```
38
+ */
39
+ export function accountIsCreated<
40
+ TAccount extends EncodedAccount | MaybeEncodedAccount,
41
+ >(
42
+ account: TAccount,
43
+ ): account is Exclude<TAccount, { readonly exists: false }> & {
44
+ readonly uncreated?: never;
45
+ } {
46
+ const maybeAccount: EncodedAccount | MaybeEncodedAccount = account;
47
+ if ('exists' in maybeAccount && !maybeAccount.exists) return false;
48
+ return !(
49
+ maybeAccount.programAddress === SYSTEM_PROGRAM_ADDRESS &&
50
+ maybeAccount.data.length === 0
51
+ );
52
+ }
package/src/dex/trade.ts CHANGED
@@ -19,7 +19,7 @@ export interface DexTradeParams {
19
19
  partner: PartnerInput;
20
20
  platformConfig: Address;
21
21
  quoteTokenProgram: Address;
22
- /** Token-2022 schedule for the epoch the trade lands in; stale or missing skews the slippage bounds. */
22
+ /** The quote mint's transfer fee for the epoch the trade lands in. A missing or old fee gives wrong slippage bounds. */
23
23
  quoteFee?: MintFee;
24
24
  baseFee?: MintFee;
25
25
  /** {@inheritDoc DexInstructionParams.userQuoteAccount} */
@@ -36,16 +36,15 @@ export interface DexInstructionParams {
36
36
  partner: PartnerInput;
37
37
  platformConfig: Address;
38
38
  quoteTokenProgram: Address;
39
- /** Any user-owned quote-mint account. Defaults to the ATA, created mid-trade
40
- * if missing (payer funds rent), which only rescues a sell. For WSOL,
41
- * a throwaway `createAccountWithSeed` account is cheaper. */
39
+ /** Any quote-mint token account that `user` owns. Defaults to the user's ATA.
40
+ * The program creates a missing ATA, and `payer` pays the rent. */
42
41
  userQuoteAccount?: Address;
43
- /** Any user-owned base-mint account. Defaults to the ATA, created mid-trade
44
- * if missing (payer funds rent), which only rescues a buy. */
42
+ /** Any base-mint token account that `user` owns. Defaults to the user's ATA.
43
+ * The program creates a missing ATA, and `payer` pays the rent. */
45
44
  userBaseAccount?: Address;
46
45
  }
47
46
 
48
- /** `baseAmountOut` is net to the buyer: the program reads `amount` as `base_to_user`. */
47
+ /** `baseAmountOut` is the base the buyer receives, after the base mint's transfer fee. */
49
48
  export async function buyExactOut(
50
49
  params: DexTradeParams & { baseAmountOut: bigint },
51
50
  ): Promise<{ instruction: Instruction; quote: BuyQuote }> {
@@ -57,7 +56,7 @@ export async function buyExactOut(
57
56
  quoteFee: params.quoteFee,
58
57
  baseFee: params.baseFee,
59
58
  });
60
- // The cap is measured on the gross the buyer sends, quote transfer fee included.
59
+ // The program checks `maxAmountIn` against the gross the buyer sends, quote transfer fee included.
61
60
  const maxQuoteIn = amm.calculateSlippageUp(
62
61
  quote.quoteFromUser,
63
62
  params.slippageBps,
@@ -83,7 +82,7 @@ export async function buyExactIn(
83
82
  quoteFee: params.quoteFee,
84
83
  baseFee: params.baseFee,
85
84
  });
86
- // The floor is measured on the buyer's credit, not the vault's debit.
85
+ // The program checks `minAmountOut` against what the buyer receives, not the vault's debit.
87
86
  const minBaseOut = amm.calculateSlippageDown(
88
87
  quote.baseToUser,
89
88
  params.slippageBps,
@@ -109,7 +108,7 @@ export async function sellExactIn(
109
108
  quoteFee: params.quoteFee,
110
109
  baseFee: params.baseFee,
111
110
  });
112
- // The floor is measured on the seller's credit, not what leaves the vault.
111
+ // The program checks `minAmountOut` against what the seller receives, not the vault's debit.
113
112
  const minQuoteOut = amm.calculateSlippageDown(
114
113
  quote.quoteToUser,
115
114
  params.slippageBps,
@@ -124,7 +123,7 @@ export async function sellExactIn(
124
123
  };
125
124
  }
126
125
 
127
- /** `quoteAmountOut` is net to the seller: the program reads `amount` as `quote_to_user`. */
126
+ /** `quoteAmountOut` is the quote the seller receives, after the quote mint's transfer fee. */
128
127
  export async function sellExactOut(
129
128
  params: DexTradeParams & { quoteAmountOut: bigint },
130
129
  ): Promise<{ instruction: Instruction; quote: SellQuote }> {
@@ -136,7 +135,7 @@ export async function sellExactOut(
136
135
  quoteFee: params.quoteFee,
137
136
  baseFee: params.baseFee,
138
137
  });
139
- // The cap is measured on the gross the seller sends, base transfer fee included.
138
+ // The program checks `maxAmountIn` against the gross the seller sends, base transfer fee included.
140
139
  const maxBaseIn = amm.calculateSlippageUp(
141
140
  quote.baseFromUser,
142
141
  params.slippageBps,
@@ -204,7 +203,7 @@ function resolveSharedAccounts(params: DexInstructionParams) {
204
203
  partner: params.partner,
205
204
  platformConfig: params.platformConfig,
206
205
  quoteTokenProgram: params.quoteTokenProgram,
207
- // Left undefined so the generated client derives the ATA itself.
206
+ // When omitted, the generated client derives the ATA.
208
207
  ...(params.userQuoteAccount !== undefined && {
209
208
  userQuoteAccount: params.userQuoteAccount,
210
209
  }),
@@ -1,27 +1,26 @@
1
1
  import type { Address, Instruction, TransactionSigner } from '@solana/kit';
2
2
  import type { MintFee, TradeQuote } from '../math/amm.js';
3
3
  import type { PartnerInput } from '../utils/partner.js';
4
- import { creatorHashFromId } from '../utils/creator-hash.js';
5
- import { findCreatorFeeConfigPda } from '../nexus/generated/pdas/creatorFeeConfig.js';
6
4
  import { getCreateTokenInstructionAsync } from './generated/instructions/createToken.js';
7
5
  import { buyExactIn } from './trade.js';
8
6
 
9
7
  export interface CreateTokenParams {
10
8
  user: TransactionSigner;
11
9
  payer?: TransactionSigner;
10
+ /** The wallet that claims the creator fees. */
12
11
  coinCreator: Address;
13
12
  baseMint: TransactionSigner;
14
13
  quoteMint: Address;
15
14
  name: string;
16
15
  symbol: string;
17
16
  uri: string;
18
- /** An enabled nexus auth platform (e.g. "wallet"), max 32 bytes; hashed with
19
- * `creatorId` into the creator fee identity. Unrelated to `platformConfig`. */
20
- creatorPlatform: string;
21
- creatorId: string;
22
17
  partner: PartnerInput;
23
18
  platformConfig: Address;
24
19
  quoteTokenProgram: Address;
20
+ creatorFeeMode: number;
21
+ creatorFeeBps: number;
22
+ /** The creator fee of the pool after migration, in bps. */
23
+ dexCreatorFeeBps: number;
25
24
  }
26
25
 
27
26
  export interface CreateAndBuyParams extends CreateTokenParams {
@@ -30,62 +29,39 @@ export interface CreateAndBuyParams extends CreateTokenParams {
30
29
  slippageBps: number;
31
30
  initialVirtualQuoteReserves: bigint;
32
31
  initialVirtualBaseReserves: bigint;
33
- /** `globalConfig.initialRealBaseReserves`: caps the appended buy. */
32
+ /** `globalConfig.initialRealBaseReserves`. Caps the buy. */
34
33
  initialRealBaseReserves: bigint;
35
- /** Quote mint's Token-2022 schedule for the launch epoch; without it `minAmountOut`
36
- * ignores the mint's cut, and a cut above `slippageBps` can revert the buy. No
37
- * `baseFee`: this transaction creates the base mint without the extension. */
34
+ /** The quote mint's transfer fee for the epoch the launch lands in. Without it, `minAmountOut`
35
+ * ignores the mint's cut, and a cut above `slippageBps` can make the buy fail. The new base
36
+ * mint has no transfer fee. */
38
37
  quoteFee?: MintFee;
39
38
  }
40
39
 
41
40
  export async function buildCreateTokenInstruction(
42
41
  params: CreateTokenParams,
43
42
  ): Promise<Instruction> {
44
- return buildCreateTokenInstructionWithHash(
45
- params,
46
- await creatorHashFromId(params.creatorPlatform, params.creatorId),
47
- );
48
- }
49
-
50
- async function buildCreateTokenInstructionWithHash(
51
- params: CreateTokenParams,
52
- creatorHash: Address,
53
- ): Promise<Instruction> {
54
- const [creatorFeeConfig] = await findCreatorFeeConfigPda({
55
- creatorHash,
56
- quoteMint: params.quoteMint,
57
- });
58
- // The creation fee is native SOL from `user`; the client derives the WSOL staking vault.
59
43
  return getCreateTokenInstructionAsync({
60
44
  user: params.user,
61
45
  payer: params.payer ?? params.user,
62
46
  coinCreator: params.coinCreator,
63
47
  baseMint: params.baseMint,
64
48
  quoteMint: params.quoteMint,
65
- creatorFeeConfig,
66
49
  partner: params.partner,
67
50
  platformConfig: params.platformConfig,
68
51
  quoteTokenProgram: params.quoteTokenProgram,
69
- creatorPlatform: params.creatorPlatform,
70
- creatorId: params.creatorId,
71
- creatorHash,
72
52
  name: params.name,
73
53
  symbol: params.symbol,
74
54
  uri: params.uri,
55
+ creatorFeeMode: params.creatorFeeMode,
56
+ creatorFeeBps: params.creatorFeeBps,
57
+ dexCreatorFeeBps: params.dexCreatorFeeBps,
75
58
  });
76
59
  }
77
60
 
78
61
  export async function buildCreateAndBuyInstructions(
79
62
  params: CreateAndBuyParams,
80
63
  ): Promise<{ instructions: Instruction[]; quote?: TradeQuote }> {
81
- const creatorHash = await creatorHashFromId(
82
- params.creatorPlatform,
83
- params.creatorId,
84
- );
85
- const createIx = await buildCreateTokenInstructionWithHash(
86
- params,
87
- creatorHash,
88
- );
64
+ const createIx = await buildCreateTokenInstruction(params);
89
65
  const instructions: Instruction[] = [createIx];
90
66
  let quote: TradeQuote | undefined;
91
67
 
@@ -98,7 +74,6 @@ export async function buildCreateAndBuyInstructions(
98
74
  virtualQuoteReserves: params.initialVirtualQuoteReserves,
99
75
  virtualBaseReserves: params.initialVirtualBaseReserves,
100
76
  realBaseReserves: params.initialRealBaseReserves,
101
- // The curve was just stamped with this same key.
102
77
  platformConfig: params.platformConfig,
103
78
  feeBps: params.feeBps,
104
79
  slippageBps: params.slippageBps,
@@ -18,12 +18,16 @@ import {
18
18
  fixEncoderSize,
19
19
  getAddressDecoder,
20
20
  getAddressEncoder,
21
+ getArrayDecoder,
22
+ getArrayEncoder,
21
23
  getBytesDecoder,
22
24
  getBytesEncoder,
23
25
  getI64Decoder,
24
26
  getI64Encoder,
25
27
  getStructDecoder,
26
28
  getStructEncoder,
29
+ getU16Decoder,
30
+ getU16Encoder,
27
31
  getU64Decoder,
28
32
  getU64Encoder,
29
33
  getU8Decoder,
@@ -42,6 +46,7 @@ import {
42
46
  type ReadonlyUint8Array,
43
47
  } from '@solana/kit';
44
48
  import { SEND_LAUNCHPAD_PROGRAM_ADDRESS } from '../programs/index.js';
49
+ import { accountIsCreated } from '../shared/index.js';
45
50
  import {
46
51
  getBondingCurveStatusDecoder,
47
52
  getBondingCurveStatusEncoder,
@@ -73,7 +78,7 @@ export type BondingCurve = {
73
78
  quoteMint: Address;
74
79
  quoteDecimals: number;
75
80
  coinCreator: Address;
76
- creatorFeeConfig: Address;
81
+ padding0: Array<bigint>;
77
82
  partner: Address;
78
83
  baseVault: Address;
79
84
  quoteVault: Address;
@@ -85,6 +90,9 @@ export type BondingCurve = {
85
90
  protocolOwed: bigint;
86
91
  creatorOwed: bigint;
87
92
  platformConfig: Address;
93
+ creatorFeeMode: number;
94
+ creatorFeeBps: number;
95
+ dexCreatorFeeBps: number;
88
96
  reserved: ReadonlyUint8Array;
89
97
  };
90
98
 
@@ -101,7 +109,7 @@ export type BondingCurveArgs = {
101
109
  quoteMint: Address;
102
110
  quoteDecimals: number;
103
111
  coinCreator: Address;
104
- creatorFeeConfig: Address;
112
+ padding0: Array<number | bigint>;
105
113
  partner: Address;
106
114
  baseVault: Address;
107
115
  quoteVault: Address;
@@ -113,6 +121,9 @@ export type BondingCurveArgs = {
113
121
  protocolOwed: number | bigint;
114
122
  creatorOwed: number | bigint;
115
123
  platformConfig: Address;
124
+ creatorFeeMode: number;
125
+ creatorFeeBps: number;
126
+ dexCreatorFeeBps: number;
116
127
  reserved: ReadonlyUint8Array;
117
128
  };
118
129
 
@@ -133,7 +144,7 @@ export function getBondingCurveEncoder(): FixedSizeEncoder<BondingCurveArgs> {
133
144
  ['quoteMint', getAddressEncoder()],
134
145
  ['quoteDecimals', getU8Encoder()],
135
146
  ['coinCreator', getAddressEncoder()],
136
- ['creatorFeeConfig', getAddressEncoder()],
147
+ ['padding0', getArrayEncoder(getU64Encoder(), { size: 4 })],
137
148
  ['partner', getAddressEncoder()],
138
149
  ['baseVault', getAddressEncoder()],
139
150
  ['quoteVault', getAddressEncoder()],
@@ -145,7 +156,10 @@ export function getBondingCurveEncoder(): FixedSizeEncoder<BondingCurveArgs> {
145
156
  ['protocolOwed', getU64Encoder()],
146
157
  ['creatorOwed', getU64Encoder()],
147
158
  ['platformConfig', getAddressEncoder()],
148
- ['reserved', fixEncoderSize(getBytesEncoder(), 64)],
159
+ ['creatorFeeMode', getU8Encoder()],
160
+ ['creatorFeeBps', getU16Encoder()],
161
+ ['dexCreatorFeeBps', getU16Encoder()],
162
+ ['reserved', fixEncoderSize(getBytesEncoder(), 256)],
149
163
  ]),
150
164
  (value) => ({ ...value, discriminator: BONDING_CURVE_DISCRIMINATOR }),
151
165
  );
@@ -167,7 +181,7 @@ export function getBondingCurveDecoder(): FixedSizeDecoder<BondingCurve> {
167
181
  ['quoteMint', getAddressDecoder()],
168
182
  ['quoteDecimals', getU8Decoder()],
169
183
  ['coinCreator', getAddressDecoder()],
170
- ['creatorFeeConfig', getAddressDecoder()],
184
+ ['padding0', getArrayDecoder(getU64Decoder(), { size: 4 })],
171
185
  ['partner', getAddressDecoder()],
172
186
  ['baseVault', getAddressDecoder()],
173
187
  ['quoteVault', getAddressDecoder()],
@@ -179,7 +193,10 @@ export function getBondingCurveDecoder(): FixedSizeDecoder<BondingCurve> {
179
193
  ['protocolOwed', getU64Decoder()],
180
194
  ['creatorOwed', getU64Decoder()],
181
195
  ['platformConfig', getAddressDecoder()],
182
- ['reserved', fixDecoderSize(getBytesDecoder(), 64)],
196
+ ['creatorFeeMode', getU8Decoder()],
197
+ ['creatorFeeBps', getU16Decoder()],
198
+ ['dexCreatorFeeBps', getU16Decoder()],
199
+ ['reserved', fixDecoderSize(getBytesDecoder(), 256)],
183
200
  ]);
184
201
  }
185
202
 
@@ -191,9 +208,25 @@ export function getBondingCurveCodec(): FixedSizeCodec<
191
208
  return combineCodec(getBondingCurveEncoder(), getBondingCurveDecoder());
192
209
  }
193
210
 
211
+ /**
212
+ * Decodes a `BondingCurve` account, throwing when another program owns it or its discriminator
213
+ * does not match.
214
+ *
215
+ * Unlike {@link fetchMaybeBondingCurve}, this throws for an address that only holds lamports rather
216
+ * than returning the non-existing variant: an account passed as existing must never come back as that
217
+ * variant typed as an `Account`. Apply {@link accountIsCreated} first to accounts fetched another way.
218
+ */
194
219
  export function decodeBondingCurve<TAddress extends string = string>(
195
220
  encodedAccount: EncodedAccount<TAddress>,
196
221
  ): Account<BondingCurve, TAddress>;
222
+ /**
223
+ * Decodes a `BondingCurve` account, throwing when another program owns it or its discriminator
224
+ * does not match.
225
+ *
226
+ * Unlike {@link fetchMaybeBondingCurve}, this throws for an address that only holds lamports rather
227
+ * than returning the non-existing variant: an account passed as existing must never come back as that
228
+ * variant typed as an `Account`. Apply {@link accountIsCreated} first to accounts fetched another way.
229
+ */
197
230
  export function decodeBondingCurve<TAddress extends string = string>(
198
231
  encodedAccount: MaybeEncodedAccount<TAddress>,
199
232
  ): MaybeAccount<BondingCurve, TAddress>;
@@ -224,6 +257,7 @@ export function decodeBondingCurve<TAddress extends string = string>(
224
257
  );
225
258
  }
226
259
 
260
+ /** Fetches a `BondingCurve` account, throwing when it does not exist or only holds lamports. */
227
261
  export async function fetchBondingCurve<TAddress extends string = string>(
228
262
  rpc: Parameters<typeof fetchEncodedAccount>[0],
229
263
  address: Address<TAddress>,
@@ -234,15 +268,25 @@ export async function fetchBondingCurve<TAddress extends string = string>(
234
268
  return maybeAccount;
235
269
  }
236
270
 
271
+ /**
272
+ * Fetches a `BondingCurve` account, or the non-existing variant when the address holds no
273
+ * account or only lamports (see {@link accountIsCreated}).
274
+ * {@link decodeBondingCurve} throws for a lamports-only account instead.
275
+ */
237
276
  export async function fetchMaybeBondingCurve<TAddress extends string = string>(
238
277
  rpc: Parameters<typeof fetchEncodedAccount>[0],
239
278
  address: Address<TAddress>,
240
279
  config?: FetchAccountConfig,
241
280
  ): Promise<MaybeAccount<BondingCurve, TAddress>> {
242
281
  const maybeAccount = await fetchEncodedAccount(rpc, address, config);
243
- return decodeBondingCurve(maybeAccount);
282
+ return decodeBondingCurve(
283
+ accountIsCreated(maybeAccount)
284
+ ? maybeAccount
285
+ : { address, exists: false },
286
+ );
244
287
  }
245
288
 
289
+ /** Fetches `BondingCurve` accounts, throwing when any does not exist or only holds lamports. */
246
290
  export async function fetchAllBondingCurve(
247
291
  rpc: Parameters<typeof fetchEncodedAccounts>[0],
248
292
  addresses: Array<Address>,
@@ -257,6 +301,11 @@ export async function fetchAllBondingCurve(
257
301
  return maybeAccounts;
258
302
  }
259
303
 
304
+ /**
305
+ * Fetches `BondingCurve` accounts, with the non-existing variant for each address that holds
306
+ * no account or only lamports (see {@link accountIsCreated}).
307
+ * {@link decodeBondingCurve} throws for a lamports-only account instead.
308
+ */
260
309
  export async function fetchAllMaybeBondingCurve(
261
310
  rpc: Parameters<typeof fetchEncodedAccounts>[0],
262
311
  addresses: Array<Address>,
@@ -264,10 +313,14 @@ export async function fetchAllMaybeBondingCurve(
264
313
  ): Promise<MaybeAccount<BondingCurve>[]> {
265
314
  const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
266
315
  return maybeAccounts.map((maybeAccount) =>
267
- decodeBondingCurve(maybeAccount),
316
+ decodeBondingCurve(
317
+ accountIsCreated(maybeAccount)
318
+ ? maybeAccount
319
+ : { address: maybeAccount.address, exists: false },
320
+ ),
268
321
  );
269
322
  }
270
323
 
271
324
  export function getBondingCurveSize(): number {
272
- return 421;
325
+ return 618;
273
326
  }
@@ -42,6 +42,7 @@ import {
42
42
  type ReadonlyUint8Array,
43
43
  } from '@solana/kit';
44
44
  import { SEND_LAUNCHPAD_PROGRAM_ADDRESS } from '../programs/index.js';
45
+ import { accountIsCreated } from '../shared/index.js';
45
46
 
46
47
  export const GLOBAL_CONFIG_DISCRIMINATOR: ReadonlyUint8Array = new Uint8Array([
47
48
  149, 8, 156, 202, 160, 252, 176, 217,
@@ -129,9 +130,25 @@ export function getGlobalConfigCodec(): FixedSizeCodec<
129
130
  return combineCodec(getGlobalConfigEncoder(), getGlobalConfigDecoder());
130
131
  }
131
132
 
133
+ /**
134
+ * Decodes a `GlobalConfig` account, throwing when another program owns it or its discriminator
135
+ * does not match.
136
+ *
137
+ * Unlike {@link fetchMaybeGlobalConfig}, this throws for an address that only holds lamports rather
138
+ * than returning the non-existing variant: an account passed as existing must never come back as that
139
+ * variant typed as an `Account`. Apply {@link accountIsCreated} first to accounts fetched another way.
140
+ */
132
141
  export function decodeGlobalConfig<TAddress extends string = string>(
133
142
  encodedAccount: EncodedAccount<TAddress>,
134
143
  ): Account<GlobalConfig, TAddress>;
144
+ /**
145
+ * Decodes a `GlobalConfig` account, throwing when another program owns it or its discriminator
146
+ * does not match.
147
+ *
148
+ * Unlike {@link fetchMaybeGlobalConfig}, this throws for an address that only holds lamports rather
149
+ * than returning the non-existing variant: an account passed as existing must never come back as that
150
+ * variant typed as an `Account`. Apply {@link accountIsCreated} first to accounts fetched another way.
151
+ */
135
152
  export function decodeGlobalConfig<TAddress extends string = string>(
136
153
  encodedAccount: MaybeEncodedAccount<TAddress>,
137
154
  ): MaybeAccount<GlobalConfig, TAddress>;
@@ -162,6 +179,7 @@ export function decodeGlobalConfig<TAddress extends string = string>(
162
179
  );
163
180
  }
164
181
 
182
+ /** Fetches a `GlobalConfig` account, throwing when it does not exist or only holds lamports. */
165
183
  export async function fetchGlobalConfig<TAddress extends string = string>(
166
184
  rpc: Parameters<typeof fetchEncodedAccount>[0],
167
185
  address: Address<TAddress>,
@@ -172,15 +190,25 @@ export async function fetchGlobalConfig<TAddress extends string = string>(
172
190
  return maybeAccount;
173
191
  }
174
192
 
193
+ /**
194
+ * Fetches a `GlobalConfig` account, or the non-existing variant when the address holds no
195
+ * account or only lamports (see {@link accountIsCreated}).
196
+ * {@link decodeGlobalConfig} throws for a lamports-only account instead.
197
+ */
175
198
  export async function fetchMaybeGlobalConfig<TAddress extends string = string>(
176
199
  rpc: Parameters<typeof fetchEncodedAccount>[0],
177
200
  address: Address<TAddress>,
178
201
  config?: FetchAccountConfig,
179
202
  ): Promise<MaybeAccount<GlobalConfig, TAddress>> {
180
203
  const maybeAccount = await fetchEncodedAccount(rpc, address, config);
181
- return decodeGlobalConfig(maybeAccount);
204
+ return decodeGlobalConfig(
205
+ accountIsCreated(maybeAccount)
206
+ ? maybeAccount
207
+ : { address, exists: false },
208
+ );
182
209
  }
183
210
 
211
+ /** Fetches `GlobalConfig` accounts, throwing when any does not exist or only holds lamports. */
184
212
  export async function fetchAllGlobalConfig(
185
213
  rpc: Parameters<typeof fetchEncodedAccounts>[0],
186
214
  addresses: Array<Address>,
@@ -195,6 +223,11 @@ export async function fetchAllGlobalConfig(
195
223
  return maybeAccounts;
196
224
  }
197
225
 
226
+ /**
227
+ * Fetches `GlobalConfig` accounts, with the non-existing variant for each address that holds
228
+ * no account or only lamports (see {@link accountIsCreated}).
229
+ * {@link decodeGlobalConfig} throws for a lamports-only account instead.
230
+ */
198
231
  export async function fetchAllMaybeGlobalConfig(
199
232
  rpc: Parameters<typeof fetchEncodedAccounts>[0],
200
233
  addresses: Array<Address>,
@@ -202,7 +235,11 @@ export async function fetchAllMaybeGlobalConfig(
202
235
  ): Promise<MaybeAccount<GlobalConfig>[]> {
203
236
  const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
204
237
  return maybeAccounts.map((maybeAccount) =>
205
- decodeGlobalConfig(maybeAccount),
238
+ decodeGlobalConfig(
239
+ accountIsCreated(maybeAccount)
240
+ ? maybeAccount
241
+ : { address: maybeAccount.address, exists: false },
242
+ ),
206
243
  );
207
244
  }
208
245