@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
@@ -98,12 +98,16 @@ export const SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_WRONG_MINT = 0x1b61; // 7009
98
98
  export const SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_WRONG_AUTHORITY = 0x1b62; // 7010
99
99
  /** NothingToClaim: Nothing to claim */
100
100
  export const SEND_NEXUS_ERROR__NOTHING_TO_CLAIM = 0x1b63; // 7011
101
- /** InvalidCreatorId: Creator identity is not a decodable wallet address */
102
- export const SEND_NEXUS_ERROR__INVALID_CREATOR_ID = 0x1b64; // 7012
101
+ /** Unused7012: Unused */
102
+ export const SEND_NEXUS_ERROR__UNUSED7012 = 0x1b64; // 7012
103
103
  /** QuoteMintPriceUnset: Quote mint has no USDC price on its nexus reward state */
104
104
  export const SEND_NEXUS_ERROR__QUOTE_MINT_PRICE_UNSET = 0x1b65; // 7013
105
105
  /** TransferFeeNotSettleable: Token-2022 transfer fee schedule cannot settle the exact amount */
106
106
  export const SEND_NEXUS_ERROR__TRANSFER_FEE_NOT_SETTLEABLE = 0x1b66; // 7014
107
+ /** CreatorFeeTooHigh: Creator fee exceeds the partner's maximum */
108
+ export const SEND_NEXUS_ERROR__CREATOR_FEE_TOO_HIGH = 0x1b67; // 7015
109
+ /** CreatorFeeModeNotAllowed: Creator fee mode is not allowed by the partner config */
110
+ export const SEND_NEXUS_ERROR__CREATOR_FEE_MODE_NOT_ALLOWED = 0x1b68; // 7016
107
111
  /** InsufficientLiquidity: Insufficient liquidity */
108
112
  export const SEND_NEXUS_ERROR__INSUFFICIENT_LIQUIDITY = 0x1bbc; // 7100
109
113
  /** InvalidAmount: Invalid amount */
@@ -112,6 +116,8 @@ export const SEND_NEXUS_ERROR__INVALID_AMOUNT = 0x1bbd; // 7101
112
116
  export type SendNexusError =
113
117
  | typeof SEND_NEXUS_ERROR__AMBIGUOUS_FEE_SOURCE
114
118
  | typeof SEND_NEXUS_ERROR__ARITHMETIC_OVERFLOW
119
+ | typeof SEND_NEXUS_ERROR__CREATOR_FEE_MODE_NOT_ALLOWED
120
+ | typeof SEND_NEXUS_ERROR__CREATOR_FEE_TOO_HIGH
115
121
  | typeof SEND_NEXUS_ERROR__DUPLICATE_AUTH_PLATFORM_NAME
116
122
  | typeof SEND_NEXUS_ERROR__INSUFFICIENT_LIQUIDITY
117
123
  | typeof SEND_NEXUS_ERROR__INSUFFICIENT_STAKE
@@ -119,7 +125,6 @@ export type SendNexusError =
119
125
  | typeof SEND_NEXUS_ERROR__INVALID_AUTHORITY
120
126
  | typeof SEND_NEXUS_ERROR__INVALID_AUTH_PLATFORM_INDEX
121
127
  | typeof SEND_NEXUS_ERROR__INVALID_AUTH_PLATFORM_NAME
122
- | typeof SEND_NEXUS_ERROR__INVALID_CREATOR_ID
123
128
  | typeof SEND_NEXUS_ERROR__INVALID_DESTINATION
124
129
  | typeof SEND_NEXUS_ERROR__INVALID_FEE_PRESET
125
130
  | typeof SEND_NEXUS_ERROR__INVALID_MINT
@@ -153,6 +158,7 @@ export type SendNexusError =
153
158
  | typeof SEND_NEXUS_ERROR__TOO_MANY_AUTH_PLATFORMS
154
159
  | typeof SEND_NEXUS_ERROR__TRANSFER_FEE_NOT_SETTLEABLE
155
160
  | typeof SEND_NEXUS_ERROR__UNAUTHORIZED
161
+ | typeof SEND_NEXUS_ERROR__UNUSED7012
156
162
  | typeof SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_INVALID
157
163
  | typeof SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_WRONG_AUTHORITY
158
164
  | typeof SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_WRONG_MINT
@@ -161,6 +167,8 @@ export type SendNexusError =
161
167
  export const sendNexusErrorMessages: Record<SendNexusError, string> = {
162
168
  [SEND_NEXUS_ERROR__AMBIGUOUS_FEE_SOURCE]: `Cannot specify both fee_preset and custom_fees`,
163
169
  [SEND_NEXUS_ERROR__ARITHMETIC_OVERFLOW]: `Arithmetic overflow`,
170
+ [SEND_NEXUS_ERROR__CREATOR_FEE_MODE_NOT_ALLOWED]: `Creator fee mode is not allowed by the partner config`,
171
+ [SEND_NEXUS_ERROR__CREATOR_FEE_TOO_HIGH]: `Creator fee exceeds the partner's maximum`,
164
172
  [SEND_NEXUS_ERROR__DUPLICATE_AUTH_PLATFORM_NAME]: `Duplicate auth platform name`,
165
173
  [SEND_NEXUS_ERROR__INSUFFICIENT_LIQUIDITY]: `Insufficient liquidity`,
166
174
  [SEND_NEXUS_ERROR__INSUFFICIENT_STAKE]: `Insufficient stake balance`,
@@ -168,7 +176,6 @@ export const sendNexusErrorMessages: Record<SendNexusError, string> = {
168
176
  [SEND_NEXUS_ERROR__INVALID_AUTHORITY]: `Invalid authority`,
169
177
  [SEND_NEXUS_ERROR__INVALID_AUTH_PLATFORM_INDEX]: `Invalid auth platform index`,
170
178
  [SEND_NEXUS_ERROR__INVALID_AUTH_PLATFORM_NAME]: `Invalid auth platform name`,
171
- [SEND_NEXUS_ERROR__INVALID_CREATOR_ID]: `Creator identity is not a decodable wallet address`,
172
179
  [SEND_NEXUS_ERROR__INVALID_DESTINATION]: `Invalid destination account`,
173
180
  [SEND_NEXUS_ERROR__INVALID_FEE_PRESET]: `Invalid fee configuration`,
174
181
  [SEND_NEXUS_ERROR__INVALID_MINT]: `Invalid mint`,
@@ -202,6 +209,7 @@ export const sendNexusErrorMessages: Record<SendNexusError, string> = {
202
209
  [SEND_NEXUS_ERROR__TOO_MANY_AUTH_PLATFORMS]: `Too many auth platforms (max 255)`,
203
210
  [SEND_NEXUS_ERROR__TRANSFER_FEE_NOT_SETTLEABLE]: `Token-2022 transfer fee schedule cannot settle the exact amount`,
204
211
  [SEND_NEXUS_ERROR__UNAUTHORIZED]: `Unauthorized`,
212
+ [SEND_NEXUS_ERROR__UNUSED7012]: `Unused`,
205
213
  [SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_INVALID]: `User token account is not an initialized token account`,
206
214
  [SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_WRONG_AUTHORITY]: `User token account is not owned by the trading user`,
207
215
  [SEND_NEXUS_ERROR__USER_TOKEN_ACCOUNT_WRONG_MINT]: `User token account mint does not match the trade`,
@@ -14,4 +14,5 @@ export * from './instructions/index.js';
14
14
  export * from './pdas/index.js';
15
15
  export * from './plugins/index.js';
16
16
  export * from './programs/index.js';
17
+ export * from './shared/index.js';
17
18
  export * from './types/index.js';
@@ -7,7 +7,6 @@
7
7
  */
8
8
 
9
9
  export * from './altRegistry.js';
10
- export * from './creatorFeeConfig.js';
11
10
  export * from './defaultFeePreset.js';
12
11
  export * from './defaultPartner.js';
13
12
  export * from './defaultPartnerMetadata.js';
@@ -23,11 +23,9 @@ import {
23
23
  } from '@solana/kit/program-client-core';
24
24
  import {
25
25
  fetchAllAltRegistry,
26
- fetchAllCreatorFeeConfig,
27
26
  fetchAllFeePreset,
28
27
  fetchAllGlobalConfig,
29
28
  fetchAllMaybeAltRegistry,
30
- fetchAllMaybeCreatorFeeConfig,
31
29
  fetchAllMaybeFeePreset,
32
30
  fetchAllMaybeGlobalConfig,
33
31
  fetchAllMaybePartnerConfig,
@@ -43,11 +41,9 @@ import {
43
41
  fetchAllUserRewardDebt,
44
42
  fetchAllUserStakePosition,
45
43
  fetchAltRegistry,
46
- fetchCreatorFeeConfig,
47
44
  fetchFeePreset,
48
45
  fetchGlobalConfig,
49
46
  fetchMaybeAltRegistry,
50
- fetchMaybeCreatorFeeConfig,
51
47
  fetchMaybeFeePreset,
52
48
  fetchMaybeGlobalConfig,
53
49
  fetchMaybePartnerConfig,
@@ -63,7 +59,6 @@ import {
63
59
  fetchUserRewardDebt,
64
60
  fetchUserStakePosition,
65
61
  getAltRegistryCodec,
66
- getCreatorFeeConfigCodec,
67
62
  getFeePresetCodec,
68
63
  getGlobalConfigCodec,
69
64
  getPartnerConfigCodec,
@@ -75,8 +70,6 @@ import {
75
70
  identifySendNexusAccount,
76
71
  type AltRegistry,
77
72
  type AltRegistryArgs,
78
- type CreatorFeeConfig,
79
- type CreatorFeeConfigArgs,
80
73
  type FeePreset,
81
74
  type FeePresetArgs,
82
75
  type GlobalConfig,
@@ -115,7 +108,6 @@ import {
115
108
  } from '../instructions/index.js';
116
109
  import {
117
110
  findAltRegistryPda,
118
- findCreatorFeeConfigPda,
119
111
  findDefaultFeePresetPda,
120
112
  findDefaultPartnerMetadataPda,
121
113
  findDefaultPartnerPda,
@@ -143,8 +135,6 @@ export type SendNexusPlugin = {
143
135
  export type SendNexusPluginAccounts = {
144
136
  altRegistry: ReturnType<typeof getAltRegistryCodec> &
145
137
  SelfFetchFunctions<AltRegistryArgs, AltRegistry>;
146
- creatorFeeConfig: ReturnType<typeof getCreatorFeeConfigCodec> &
147
- SelfFetchFunctions<CreatorFeeConfigArgs, CreatorFeeConfig>;
148
138
  feePreset: ReturnType<typeof getFeePresetCodec> &
149
139
  SelfFetchFunctions<FeePresetArgs, FeePreset>;
150
140
  globalConfig: ReturnType<typeof getGlobalConfigCodec> &
@@ -203,7 +193,6 @@ export type SendNexusPluginPdas = {
203
193
  userStakePosition: typeof findUserStakePositionPda;
204
194
  userRewardDebt: typeof findUserRewardDebtPda;
205
195
  eventAuthority: typeof findEventAuthorityPda;
206
- creatorFeeConfig: typeof findCreatorFeeConfigPda;
207
196
  altRegistry: typeof findAltRegistryPda;
208
197
  };
209
198
 
@@ -236,29 +225,6 @@ export function sendNexusProgram() {
236
225
  fetchMaybe: (address, config) =>
237
226
  fetchMaybeAltRegistry(client.rpc, address, config),
238
227
  }),
239
- creatorFeeConfig: Object.freeze({
240
- ...getCreatorFeeConfigCodec(),
241
- fetch: (address, config) =>
242
- fetchCreatorFeeConfig(client.rpc, address, config),
243
- fetchAll: (addresses, config) =>
244
- fetchAllCreatorFeeConfig(
245
- client.rpc,
246
- addresses,
247
- config,
248
- ),
249
- fetchAllMaybe: (addresses, config) =>
250
- fetchAllMaybeCreatorFeeConfig(
251
- client.rpc,
252
- addresses,
253
- config,
254
- ),
255
- fetchMaybe: (address, config) =>
256
- fetchMaybeCreatorFeeConfig(
257
- client.rpc,
258
- address,
259
- config,
260
- ),
261
- }),
262
228
  feePreset: Object.freeze({
263
229
  ...getFeePresetCodec(),
264
230
  fetch: (address, config) =>
@@ -480,7 +446,6 @@ export function sendNexusProgram() {
480
446
  userStakePosition: findUserStakePositionPda,
481
447
  userRewardDebt: findUserRewardDebtPda,
482
448
  eventAuthority: findEventAuthorityPda,
483
- creatorFeeConfig: findCreatorFeeConfigPda,
484
449
  altRegistry: findAltRegistryPda,
485
450
  },
486
451
  identifyAccount: identifySendNexusAccount,
@@ -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
+ }
@@ -23,7 +23,7 @@ export type DexFees = {
23
23
  creationFeeCents: bigint;
24
24
  protocolFeeBps: number;
25
25
  lpFeeBps: number;
26
- creatorFeeBps: number;
26
+ maxCreatorFeeBps: number;
27
27
  feeDecaySeconds: number;
28
28
  feeDecayStartBps: number;
29
29
  };
@@ -32,7 +32,7 @@ export type DexFeesArgs = {
32
32
  creationFeeCents: number | bigint;
33
33
  protocolFeeBps: number;
34
34
  lpFeeBps: number;
35
- creatorFeeBps: number;
35
+ maxCreatorFeeBps: number;
36
36
  feeDecaySeconds: number;
37
37
  feeDecayStartBps: number;
38
38
  };
@@ -42,7 +42,7 @@ export function getDexFeesEncoder(): FixedSizeEncoder<DexFeesArgs> {
42
42
  ['creationFeeCents', getU64Encoder()],
43
43
  ['protocolFeeBps', getU16Encoder()],
44
44
  ['lpFeeBps', getU16Encoder()],
45
- ['creatorFeeBps', getU16Encoder()],
45
+ ['maxCreatorFeeBps', getU16Encoder()],
46
46
  ['feeDecaySeconds', getU16Encoder()],
47
47
  ['feeDecayStartBps', getU16Encoder()],
48
48
  ]);
@@ -53,7 +53,7 @@ export function getDexFeesDecoder(): FixedSizeDecoder<DexFees> {
53
53
  ['creationFeeCents', getU64Decoder()],
54
54
  ['protocolFeeBps', getU16Decoder()],
55
55
  ['lpFeeBps', getU16Decoder()],
56
- ['creatorFeeBps', getU16Decoder()],
56
+ ['maxCreatorFeeBps', getU16Decoder()],
57
57
  ['feeDecaySeconds', getU16Decoder()],
58
58
  ['feeDecayStartBps', getU16Decoder()],
59
59
  ]);
@@ -7,7 +7,6 @@
7
7
  */
8
8
 
9
9
  export * from './authPlatformEntry.js';
10
- export * from './callerType.js';
11
10
  export * from './dexFees.js';
12
11
  export * from './feeConfig.js';
13
12
  export * from './launchpadFees.js';
@@ -22,7 +22,7 @@ import {
22
22
  export type LaunchpadFees = {
23
23
  creationFeeCents: bigint;
24
24
  protocolFeeBps: number;
25
- creatorFeeBps: number;
25
+ maxCreatorFeeBps: number;
26
26
  feeDecaySeconds: number;
27
27
  feeDecayStartBps: number;
28
28
  };
@@ -30,7 +30,7 @@ export type LaunchpadFees = {
30
30
  export type LaunchpadFeesArgs = {
31
31
  creationFeeCents: number | bigint;
32
32
  protocolFeeBps: number;
33
- creatorFeeBps: number;
33
+ maxCreatorFeeBps: number;
34
34
  feeDecaySeconds: number;
35
35
  feeDecayStartBps: number;
36
36
  };
@@ -39,7 +39,7 @@ export function getLaunchpadFeesEncoder(): FixedSizeEncoder<LaunchpadFeesArgs> {
39
39
  return getStructEncoder([
40
40
  ['creationFeeCents', getU64Encoder()],
41
41
  ['protocolFeeBps', getU16Encoder()],
42
- ['creatorFeeBps', getU16Encoder()],
42
+ ['maxCreatorFeeBps', getU16Encoder()],
43
43
  ['feeDecaySeconds', getU16Encoder()],
44
44
  ['feeDecayStartBps', getU16Encoder()],
45
45
  ]);
@@ -49,7 +49,7 @@ export function getLaunchpadFeesDecoder(): FixedSizeDecoder<LaunchpadFees> {
49
49
  return getStructDecoder([
50
50
  ['creationFeeCents', getU64Decoder()],
51
51
  ['protocolFeeBps', getU16Decoder()],
52
- ['creatorFeeBps', getU16Decoder()],
52
+ ['maxCreatorFeeBps', getU16Decoder()],
53
53
  ['feeDecaySeconds', getU16Decoder()],
54
54
  ['feeDecayStartBps', getU16Decoder()],
55
55
  ]);
@@ -17,6 +17,7 @@ import {
17
17
  } from '../constants.js';
18
18
  import { fetchInChunks } from '../utils/chunk.js';
19
19
  import { findAssociatedTokenPda } from '../utils/pda.js';
20
+ import { accountIsCreated } from './generated/shared/index.js';
20
21
  import { fetchStakingConfig } from './generated/accounts/stakingConfig.js';
21
22
  import {
22
23
  fetchMaybeUserStakePosition,
@@ -42,10 +43,10 @@ import { findRewardAccrualPda as findLaunchpadRewardAccrualPda } from '../launch
42
43
  import { getRewardAccrualDecoder } from '../launchpad/generated/accounts/rewardAccrual.js';
43
44
  import { findRewardAccrualPda as findDexRewardAccrualPda } from '../dex/generated/pdas/rewardAccrual.js';
44
45
 
45
- // 1e12 scale of `RewardAccrual.accPerToken` on both programs; must match send_shared `PRECISION`.
46
+ // Fixed-point scale of `RewardAccrual.accPerToken` in both programs.
46
47
  const PRECISION = 1_000_000_000_000n;
47
48
 
48
- /** `getProgramAccounts` is optional: many providers restrict it and LiteSVM lacks it, so pass `rewardMints` there. */
49
+ /** An RPC with `getAccountInfo` and, optionally, `getProgramAccounts`. Without `getProgramAccounts`, pass `rewardMints`. */
49
50
  export type RewardMintRpc = Rpc<GetAccountInfoApi> &
50
51
  Partial<Rpc<GetProgramAccountsApi>>;
51
52
 
@@ -55,7 +56,7 @@ function hasProgramAccounts(
55
56
  return typeof rpc.getProgramAccounts === 'function';
56
57
  }
57
58
 
58
- // On-chain body offsets + 8 for the discriminator; pinned by tests/staking.test.ts.
59
+ // Field offsets, including the 8-byte discriminator. tests/staking.test.ts pins them.
59
60
  const REWARD_STATE_STAKING_CONFIG_OFFSET = 10n;
60
61
  const REWARD_STATE_REWARD_MINT_OFFSET = 42;
61
62
 
@@ -65,9 +66,8 @@ function compareAddresses(a: Address, b: Address): number {
65
66
  return 0;
66
67
  }
67
68
 
68
- /** Registered reward mints, sorted by address. Includes disabled mints: their accrued balance is
69
- * still owed and the settle gate still counts them. Throws when the sweep disagrees with
70
- * `StakingConfig.rewardCount` rather than settle a short list. */
69
+ /** Returns every registered reward mint, disabled mints included, sorted by address.
70
+ * Throws if the count differs from `StakingConfig.rewardCount`. */
71
71
  export async function getRewardMints(
72
72
  rpc: Rpc<GetAccountInfoApi> & Rpc<GetProgramAccountsApi>,
73
73
  ): Promise<readonly Address[]> {
@@ -98,7 +98,7 @@ export async function getRewardMints(
98
98
  const mints: Address[] = [];
99
99
  for (const { account } of accounts) {
100
100
  const data = base64.encode(account.data[0]);
101
- // Another nexus account of the same size could pass both filters.
101
+ // Another nexus account of the same size can pass both filters.
102
102
  if (!containsBytes(data, REWARD_STATE_DISCRIMINATOR, 0)) continue;
103
103
  mints.push(
104
104
  addressDecoder.decode(data, REWARD_STATE_REWARD_MINT_OFFSET),
@@ -136,13 +136,14 @@ async function resolveRewardMints(
136
136
  }
137
137
 
138
138
  export interface SettleParams {
139
- /** `settle` is permissionless: the user does not sign. */
139
+ /** Does not sign. `settle` is permissionless. */
140
140
  user: Address;
141
141
  payer: TransactionSigner;
142
142
  stakingMint: Address;
143
143
  }
144
144
 
145
- /** One idempotent `settle` per mint; a partial mint list leaves `stake` and `unstake` failing `RewardsNotSettled`. */
145
+ /** Builds one `settle` per reward mint. `source` is the mint list, or an RPC to read it from.
146
+ * `settle` is idempotent. With a partial list, `stake` and `unstake` fail with `RewardsNotSettled`. */
146
147
  export async function buildSettleInstructions(
147
148
  source: RewardMintSource,
148
149
  params: SettleParams,
@@ -187,7 +188,7 @@ export async function fetchMissingUserRewardDebts(
187
188
 
188
189
  const missingMints: Address[] = [];
189
190
  for (const [index, rewardMint] of rewardMints.entries()) {
190
- if (!encodedAccounts[index].exists) {
191
+ if (!accountIsCreated(encodedAccounts[index])) {
191
192
  missingMints.push(rewardMint);
192
193
  }
193
194
  }
@@ -199,16 +200,17 @@ export interface PrepareStakingParams {
199
200
  user: Address;
200
201
  payer: TransactionSigner;
201
202
  stakingMint: Address;
202
- /** Must be the full registry when supplied; a subset leaves `stake` and `unstake` blocked. */
203
+ /** If given, must hold every registered mint. With a subset, `stake` and `unstake` fail. */
203
204
  rewardMints?: readonly Address[];
204
205
  }
205
206
 
206
- /** Opens missing `UserRewardDebt`s, then settles every mint; the user never signs, so the stake or unstake after is one wallet prompt. */
207
+ /** Builds a `create_user_reward_debt` for each missing `UserRewardDebt`, then a `settle` for every
208
+ * reward mint. The user does not sign these instructions. */
207
209
  export async function buildStakingPreflightInstructions(
208
210
  rpc: RewardMintRpc & Rpc<GetMultipleAccountsApi>,
209
211
  params: PrepareStakingParams,
210
212
  ): Promise<Instruction[]> {
211
- // One sweep for both halves: two sweeps can disagree.
213
+ // Read the mints once. Two reads can return different lists.
212
214
  const rewardMints = await resolveRewardMints(rpc, params.rewardMints);
213
215
 
214
216
  const missingMints = await fetchMissingUserRewardDebts(
@@ -234,7 +236,7 @@ export async function buildStakingPreflightInstructions(
234
236
  return [...createIxs, ...settleIxs];
235
237
  }
236
238
 
237
- /** True once `stake` and `unstake` will pass the `settledCount == rewardCount` gate. */
239
+ /** Returns true if `stake` and `unstake` pass the `settledCount == rewardCount` check. */
238
240
  export async function isFullySettled(
239
241
  rpc: Rpc<GetAccountInfoApi>,
240
242
  user: Address,
@@ -255,7 +257,8 @@ export interface StakeParams {
255
257
  amount: bigint;
256
258
  }
257
259
 
258
- /** Fails `RewardsNotSettled` until every mint is settled at the current `stakeVersion`; run `buildStakingPreflightInstructions` first. */
260
+ /** The instruction fails with `RewardsNotSettled` until every mint is settled at the current
261
+ * `stakeVersion`. Run `buildStakingPreflightInstructions` first. */
259
262
  export async function buildStakeInstruction(
260
263
  params: StakeParams,
261
264
  ): Promise<Instruction> {
@@ -274,8 +277,9 @@ export interface UnstakeParams {
274
277
  amount: bigint;
275
278
  }
276
279
 
277
- /** Settle immediately before via `buildStakingPreflightInstructions`: the gate passes on a stale settle,
278
- * and the window since it is then paid at the post-unstake amount, forfeiting accrual. */
280
+ /** Run `buildStakingPreflightInstructions` immediately before. The check also passes on an older
281
+ * settle. Rewards since that settle then accrue on the smaller post-unstake amount, and the
282
+ * difference is lost. */
279
283
  export async function buildUnstakeInstruction(
280
284
  params: UnstakeParams,
281
285
  ): Promise<Instruction> {
@@ -291,12 +295,12 @@ export interface ClaimRewardsParams {
291
295
  user: TransactionSigner;
292
296
  payer?: TransactionSigner;
293
297
  stakingMint: Address;
294
- /** Defaults to every registered mint; each claim settles its own mint, so a subset needs no preflight. */
298
+ /** Defaults to every registered mint. A subset needs no preflight: each `claim` settles its own mint. */
295
299
  rewardMints?: readonly Address[];
296
300
  }
297
301
 
298
- /** One `claim` per mint, preceded by `create_user_reward_debt` where the debt is missing:
299
- * `Claim` requires the account to exist, so one missing debt fails the whole transaction. */
302
+ /** Builds one `claim` per reward mint. A `create_user_reward_debt` comes before each `claim` whose
303
+ * `UserRewardDebt` is missing: `claim` fails without it. Throws if a mint has no `RewardState`. */
300
304
  export async function buildClaimRewardsInstructions(
301
305
  rpc: RewardMintRpc & Rpc<GetMultipleAccountsApi>,
302
306
  params: ClaimRewardsParams,
@@ -337,7 +341,7 @@ export async function buildClaimRewardsInstructions(
337
341
  const perMint = await Promise.all(
338
342
  rewardMints.map(async (rewardMint, index) => {
339
343
  const encodedRewardState = fetched[index];
340
- if (!encodedRewardState.exists) {
344
+ if (!accountIsCreated(encodedRewardState)) {
341
345
  throw new Error(`RewardState not found for mint ${rewardMint}`);
342
346
  }
343
347
  const { vault } = rewardStateDecoder.decode(
@@ -356,8 +360,8 @@ export async function buildClaimRewardsInstructions(
356
360
 
357
361
  const instructions: Instruction[] = [];
358
362
 
359
- // Directly before its own `claim`, so slicing the list by mint keeps each pair together.
360
- if (!fetched[rewardMints.length * 2 + index].exists) {
363
+ // Directly before its own `claim`, so a split of the list by mint keeps each pair together.
364
+ if (!accountIsCreated(fetched[rewardMints.length * 2 + index])) {
361
365
  instructions.push(
362
366
  await getCreateUserRewardDebtInstructionAsync({
363
367
  user: params.user.address,
@@ -395,12 +399,13 @@ export interface WithdrawFeesAccounts {
395
399
  tokenProgram: Address;
396
400
  }
397
401
 
398
- /** Accounts for one mint's `withdraw_fees`; call once per mint. */
402
+ /** Returns the accounts of `withdraw_fees` for one reward mint. Without `tokenProgram`, reads it
403
+ * from the mint account. Throws if that account does not exist. */
399
404
  export async function buildWithdrawFeesAccounts(
400
405
  rpc: Rpc<GetAccountInfoApi>,
401
406
  params: {
402
407
  rewardMint: Address;
403
- /** Wallet, not token account: its ATA is derived. */
408
+ /** A wallet, not a token account. The SDK derives its ATA. */
404
409
  destination: Address;
405
410
  tokenProgram?: Address;
406
411
  },
@@ -467,13 +472,12 @@ export async function fetchUserStakePositionData(
467
472
  return maybePosition.exists ? maybePosition.data : null;
468
473
  }
469
474
 
470
- /** Unbound reads as `Pubkey::default()` (the system program address), which `bind_staking_mint`
471
- * can never store: it requires a token mint. */
475
+ /** Returns false for the system program address, the value of an unbound staking mint. */
472
476
  export function isStakingMintBound(stakingMint: Address): boolean {
473
477
  return stakingMint !== SYSTEM_PROGRAM_ADDRESS;
474
478
  }
475
479
 
476
- /** The staking mint is immutable once bound, so this result is safe to cache. */
480
+ /** Returns the staking mint. Throws if no staking mint is bound. A bound staking mint cannot change. */
477
481
  export async function fetchSendMint(
478
482
  rpc: Rpc<GetAccountInfoApi>,
479
483
  ): Promise<Address> {
@@ -488,13 +492,14 @@ export async function fetchSendMint(
488
492
 
489
493
  export interface PendingReward {
490
494
  rewardMint: Address;
491
- /** Base units of `rewardMint` debited at the vault (matches `ClaimEvent.amount`); a
492
- * `TransferFeeConfig` mint delivers less -- net it with `transferFee.fetchMintFees`. */
495
+ /** Amount the vault sends, in raw units of `rewardMint`. Equals `ClaimEvent.amount`. A mint with a
496
+ * transfer fee delivers less. Get the fee with `transferFee.fetchMintFees`. */
493
497
  pending: bigint;
494
498
  }
495
499
 
496
- /** One entry per reward mint, in `knownRewardMints` order, else sorted by address. Each amount is in
497
- * its own mint's base units, so never sum them, and is the vault's debit, not the claimant's credit. */
500
+ /** Returns one entry per reward mint, in `knownRewardMints` order, else sorted by address. Each amount
501
+ * is in the raw units of its own mint. Do not add them together. Each amount is what the vault sends,
502
+ * before the mint's transfer fee. */
498
503
  export async function fetchPendingRewards(
499
504
  rpc: RewardMintRpc & Rpc<GetMultipleAccountsApi>,
500
505
  user: Address,
@@ -541,33 +546,32 @@ export async function fetchPendingRewards(
541
546
  );
542
547
 
543
548
  const userRewardDebtDecoder = getUserRewardDebtDecoder();
544
- // One decoder for both: the two `RewardAccrual` types share shape and discriminator.
549
+ // One decoder for both: the two `RewardAccrual` types have the same layout and discriminator.
545
550
  const rewardAccrualDecoder = getRewardAccrualDecoder();
546
551
 
547
552
  return pdas.map(({ rewardMint }, index) => {
548
553
  const base = index * 3;
549
554
 
550
555
  const encodedDebt = encodedAccounts[base];
551
- // A missing debt is not zero owed: `create_user_reward_debt` opens it at
552
- // `accSnapshot = 0`, `amountSnapshot = position.amount`, and the claim pays that.
553
- const debt = encodedDebt.exists
556
+ // A missing debt is not zero owed. `create_user_reward_debt` opens it at
557
+ // `accSnapshot = 0` and `amountSnapshot = position.amount`, and the claim pays from there.
558
+ const debt = accountIsCreated(encodedDebt)
554
559
  ? userRewardDebtDecoder.decode(encodedDebt.data)
555
560
  : { owed: 0n, accSnapshot: 0n, amountSnapshot: stakeAmount };
556
561
 
557
562
  const encodedLaunchpadAccrual = encodedAccounts[base + 1];
558
- const launchpadAcc = encodedLaunchpadAccrual.exists
563
+ const launchpadAcc = accountIsCreated(encodedLaunchpadAccrual)
559
564
  ? rewardAccrualDecoder.decode(encodedLaunchpadAccrual.data)
560
565
  .accPerToken
561
566
  : 0n;
562
567
 
563
568
  const encodedDexAccrual = encodedAccounts[base + 2];
564
- const dexAcc = encodedDexAccrual.exists
569
+ const dexAcc = accountIsCreated(encodedDexAccrual)
565
570
  ? rewardAccrualDecoder.decode(encodedDexAccrual.data).accPerToken
566
571
  : 0n;
567
572
 
568
- // Mirrors `settle_debt`: basis is the smaller amount (`amountSnapshot` alone over-quotes
569
- // after an unstake), floored once over the summed accumulators. A negative delta quotes 0
570
- // where the program would fail.
573
+ // Matches `settle`: the basis is the smaller amount, floored once over the summed
574
+ // accumulators. A negative delta quotes 0, where the program fails.
571
575
  const basis =
572
576
  debt.amountSnapshot < stakeAmount
573
577
  ? debt.amountSnapshot
package/src/platform.ts CHANGED
@@ -2,10 +2,10 @@ import { getProgramDerivedAddress } from '@solana/kit';
2
2
  import type { ProgramDerivedAddress } from '@solana/kit';
3
3
  import { SEND_NEXUS_PROGRAM_ADDRESS } from './nexus/generated/programs/index.js';
4
4
 
5
- /** A platform is only a key, with no on-chain account; it is a PDA so a platform account can later `init` at it. */
5
+ /** Seed of the platform PDA. A platform has no on-chain account. */
6
6
  export const PLATFORM_SEED = 'platform';
7
7
 
8
- /** The name is the platform's identity: renaming one orphans every market and partner config under the old key. */
8
+ /** Derives the platform key for `name` under the nexus program. Each name gives a different platform. */
9
9
  export async function findPlatformAddress(
10
10
  name: string,
11
11
  ): Promise<ProgramDerivedAddress> {