@soltracer/nft-staking 0.1.0 → 0.2.1

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/dist/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BN, Program } from "@coral-xyz/anchor";
2
2
  import { PublicKey, SystemProgram } from "@solana/web3.js";
3
- import { getStakeConfigPda, getStakePoolPda, getStakeEntryPda, getStakerAccountPda, getCollectionPda, getPoolAuthorityPda, getPoolSecondaryRewardsPda, getStakerSecondaryRewardsPda, getProjectPda, getAta, decodeAccount, getFeeConfigPda, getTreasuryPda, PROJECT_MANAGEMENT_PROGRAM_ID, ADMIN_PROGRAM_ID, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, MPL_CORE_PROGRAM_ID, } from "@soltracer/core";
3
+ import { getStakeConfigPda, getStakePoolPda, getStakeEntryPda, getStakerAccountPda, getCollectionPda, getPoolAuthorityPda, getPoolSecondaryRewardsPda, getStakerSecondaryRewardsPda, getProjectPda, getUtilityConfigPda, getProgramRegistryPda, getAta, decodeAccount, getFeeConfigPda, getTreasuryPda, PROJECT_MANAGEMENT_PROGRAM_ID, ADMIN_PROGRAM_ID, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, MPL_CORE_PROGRAM_ID, } from "@soltracer/core";
4
4
  import NftStakingIDL from "./idl.json";
5
5
  /** Well-known program IDs for cNFT operations. */
6
6
  const BUBBLEGUM_PROGRAM_ID = new PublicKey("BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY");
@@ -32,22 +32,70 @@ function base58HashToArray(hash) {
32
32
  function getTreeConfigPda(merkleTree) {
33
33
  return PublicKey.findProgramAddressSync([merkleTree.toBytes()], BUBBLEGUM_PROGRAM_ID);
34
34
  }
35
+ function toPk(v) {
36
+ return typeof v === "string" ? new PublicKey(v) : v;
37
+ }
38
+ function toBN(v) {
39
+ return typeof v === "number" ? new BN(v) : v;
40
+ }
35
41
  export class NftStakingClient {
36
42
  program;
37
43
  provider;
38
44
  tokenProgramCache = new Map();
39
45
  mintDecimalsCache = new Map();
40
- constructor(program, provider) {
46
+ poolCache = new Map();
47
+ static POOL_CACHE_TTL = 30_000; // 30s
48
+ /** Project ID bound to this client. Set via `create()` options or `setProjectId()`. */
49
+ projectId;
50
+ constructor(program, provider, projectId) {
41
51
  this.program = program;
42
52
  this.provider = provider;
53
+ this.projectId = projectId;
43
54
  }
44
- static create(provider) {
55
+ static create(provider, opts) {
45
56
  const program = new Program(NftStakingIDL, provider);
46
- return new NftStakingClient(program, provider);
57
+ return new NftStakingClient(program, provider, opts?.projectId);
47
58
  }
48
- static fromIdl(idl, provider) {
59
+ static fromIdl(idl, provider, opts) {
49
60
  const program = new Program(idl, provider);
50
- return new NftStakingClient(program, provider);
61
+ return new NftStakingClient(program, provider, opts?.projectId);
62
+ }
63
+ /** Set the project ID for this client instance. Returns `this` for chaining. */
64
+ setProjectId(projectId) {
65
+ this.projectId = projectId;
66
+ return this;
67
+ }
68
+ /** Resolve projectId: use explicit param if given, else fall back to instance-level. Throws if neither is set. */
69
+ resolveProjectId(projectId) {
70
+ const pid = projectId ?? this.projectId;
71
+ if (pid === undefined)
72
+ throw new Error("projectId required: pass it explicitly or set via create()/setProjectId()");
73
+ return pid;
74
+ }
75
+ /** Fetch pool data with caching. Used internally to auto-resolve rewardMint, stakingMode, collectionMint. */
76
+ async getPoolData(projectId, poolId) {
77
+ const key = `${projectId}-${poolId}`;
78
+ const cached = this.poolCache.get(key);
79
+ if (cached && Date.now() - cached.fetchedAt < NftStakingClient.POOL_CACHE_TTL) {
80
+ return cached.data;
81
+ }
82
+ const pool = await this.fetchStakePool(projectId, poolId);
83
+ if (!pool)
84
+ throw new Error(`Pool ${poolId} not found for project ${projectId}`);
85
+ this.poolCache.set(key, { data: pool, fetchedAt: Date.now() });
86
+ return pool;
87
+ }
88
+ /** Invalidate cached pool data (call after pool mutations). */
89
+ invalidatePoolCache(poolId) {
90
+ if (poolId !== undefined) {
91
+ for (const key of this.poolCache.keys()) {
92
+ if (key.endsWith(`-${poolId}`))
93
+ this.poolCache.delete(key);
94
+ }
95
+ }
96
+ else {
97
+ this.poolCache.clear();
98
+ }
51
99
  }
52
100
  /** Detect whether a mint is Token-2022 or SPL Token (cached). */
53
101
  async resolveTokenProgram(mint) {
@@ -94,6 +142,7 @@ export class NftStakingClient {
94
142
  resolveFeeAccounts(fee) {
95
143
  const programId = this.program.programId;
96
144
  const [feeConfig] = getFeeConfigPda(programId);
145
+ const [programRegistry] = getProgramRegistryPda(programId);
97
146
  const [treasury] = getTreasuryPda();
98
147
  let referralAccount = ADMIN_PROGRAM_ID;
99
148
  if (fee?.referralAccount) {
@@ -105,6 +154,7 @@ export class NftStakingClient {
105
154
  }
106
155
  return {
107
156
  feeConfig,
157
+ programRegistry,
108
158
  treasury,
109
159
  referralAccount,
110
160
  solUsdPriceFeed: NftStakingClient.PYTH_SOL_USD_FEED,
@@ -112,14 +162,16 @@ export class NftStakingClient {
112
162
  };
113
163
  }
114
164
  async fetchStakeConfig(projectId) {
115
- const [pda] = getStakeConfigPda(projectId);
165
+ const pid = this.resolveProjectId(projectId);
166
+ const [pda] = getStakeConfigPda(pid);
116
167
  const raw = await this.program.account.stakePoolConfig.fetchNullable(pda);
117
168
  if (!raw)
118
169
  return null;
119
170
  return decodeAccount(raw);
120
171
  }
121
172
  async fetchStakePool(projectId, poolId) {
122
- const [pda] = getStakePoolPda(projectId, poolId);
173
+ const pid = this.resolveProjectId(projectId);
174
+ const [pda] = getStakePoolPda(pid, poolId);
123
175
  const raw = await this.program.account.stakePool.fetchNullable(pda);
124
176
  if (!raw)
125
177
  return null;
@@ -128,14 +180,14 @@ export class NftStakingClient {
128
180
  return this.applyPoolDecimals(pool, decimals);
129
181
  }
130
182
  async fetchStakeEntry(poolId, nftMint) {
131
- const [pda] = getStakeEntryPda(poolId, nftMint);
183
+ const [pda] = getStakeEntryPda(poolId, toPk(nftMint));
132
184
  const raw = await this.program.account.stakeEntry.fetchNullable(pda);
133
185
  if (!raw)
134
186
  return null;
135
187
  return decodeAccount(raw);
136
188
  }
137
189
  async fetchStakerAccount(poolId, wallet, rewardDecimals) {
138
- const [pda] = getStakerAccountPda(poolId, wallet);
190
+ const [pda] = getStakerAccountPda(poolId, toPk(wallet));
139
191
  const raw = await this.program.account.stakerAccount.fetchNullable(pda);
140
192
  if (!raw)
141
193
  return null;
@@ -153,12 +205,13 @@ export class NftStakingClient {
153
205
  }
154
206
  /** Fetch all stake pools for a project by scanning pool IDs 0..totalPools-1. */
155
207
  async fetchAllPools(projectId) {
156
- const config = await this.fetchStakeConfig(projectId);
208
+ const pid = this.resolveProjectId(projectId);
209
+ const config = await this.fetchStakeConfig(pid);
157
210
  if (!config)
158
211
  return [];
159
212
  const pools = [];
160
213
  for (let i = 0; i < config.totalPools; i++) {
161
- const pool = await this.fetchStakePool(projectId, i);
214
+ const pool = await this.fetchStakePool(pid, i);
162
215
  if (pool)
163
216
  pools.push(pool);
164
217
  }
@@ -166,8 +219,9 @@ export class NftStakingClient {
166
219
  }
167
220
  /** Fetch all active stake entries for a wallet in a specific pool via gPA. */
168
221
  async fetchStakeEntriesByOwner(_poolId, owner) {
222
+ const _owner = toPk(owner);
169
223
  const entries = await this.program.account.stakeEntry.all([
170
- { memcmp: { offset: 72, bytes: owner.toBase58() } },
224
+ { memcmp: { offset: 72, bytes: _owner.toBase58() } },
171
225
  ]);
172
226
  return entries
173
227
  .map(({ account }) => decodeAccount(account))
@@ -180,7 +234,7 @@ export class NftStakingClient {
180
234
  async fetchStakeEntriesForMints(poolId, nftMints) {
181
235
  if (nftMints.length === 0)
182
236
  return [];
183
- const pdas = nftMints.map((mint) => getStakeEntryPda(poolId, mint)[0]);
237
+ const pdas = nftMints.map((mint) => getStakeEntryPda(poolId, toPk(mint))[0]);
184
238
  const accounts = await this.program.account.stakeEntry.fetchMultiple(pdas);
185
239
  return accounts
186
240
  .filter((a) => a !== null)
@@ -188,8 +242,9 @@ export class NftStakingClient {
188
242
  .filter((e) => e.isActive);
189
243
  }
190
244
  /** Fetch all stake entries for a pool via gPA with memcmp on pool pubkey. */
191
- async fetchAllStakeEntriesByPool(projectId, poolId) {
192
- const [poolPda] = getStakePoolPda(projectId, poolId);
245
+ async fetchAllStakeEntriesByPool(poolId, projectId) {
246
+ const pid = this.resolveProjectId(projectId);
247
+ const [poolPda] = getStakePoolPda(pid, poolId);
193
248
  const entries = await this.program.account.stakeEntry.all([
194
249
  { memcmp: { offset: 8, bytes: poolPda.toBase58() } },
195
250
  ]);
@@ -215,18 +270,21 @@ export class NftStakingClient {
215
270
  .filter((e) => e.isActive);
216
271
  }
217
272
  /** Fetch all staker accounts for a pool via gPA with memcmp on pool pubkey. */
218
- async fetchAllStakersByPool(projectId, poolId) {
219
- const [poolPda] = getStakePoolPda(projectId, poolId);
273
+ async fetchAllStakersByPool(poolId, projectId) {
274
+ const pid = this.resolveProjectId(projectId);
275
+ const [poolPda] = getStakePoolPda(pid, poolId);
220
276
  const stakers = await this.program.account.stakerAccount.all([
221
277
  { memcmp: { offset: 8, bytes: poolPda.toBase58() } },
222
278
  ]);
223
279
  return stakers.map(({ account }) => decodeAccount(account));
224
280
  }
225
- async closeLegacyCollection(projectId, collectionMint) {
226
- const [collection] = PublicKey.findProgramAddressSync([Buffer.from("project_collection"), new BN(projectId).toArrayLike(Buffer, "le", 8), collectionMint.toBuffer()], this.program.programId);
227
- const [project] = getProjectPda(projectId);
281
+ async closeLegacyCollection(collectionMint, projectId) {
282
+ const _collMint = toPk(collectionMint);
283
+ const pid = this.resolveProjectId(projectId);
284
+ const [collection] = PublicKey.findProgramAddressSync([Buffer.from("project_collection"), new BN(pid).toArrayLike(Buffer, "le", 8), _collMint.toBuffer()], this.program.programId);
285
+ const [project] = getProjectPda(pid);
228
286
  return this.program.methods
229
- .closeLegacyCollection(new BN(projectId), collectionMint)
287
+ .closeLegacyCollection(new BN(pid), _collMint)
230
288
  .accountsStrict({
231
289
  collection,
232
290
  authority: this.provider.wallet.publicKey,
@@ -236,10 +294,11 @@ export class NftStakingClient {
236
294
  .instruction();
237
295
  }
238
296
  async initializeStakeConfig(projectId) {
239
- const [config] = getStakeConfigPda(projectId);
240
- const [project] = getProjectPda(projectId);
297
+ const pid = this.resolveProjectId(projectId);
298
+ const [config] = getStakeConfigPda(pid);
299
+ const [project] = getProjectPda(pid);
241
300
  return this.program.methods
242
- .initializeStakeConfig(new BN(projectId))
301
+ .initializeStakeConfig(new BN(pid))
243
302
  .accountsStrict({
244
303
  config,
245
304
  authority: this.provider.wallet.publicKey,
@@ -249,15 +308,20 @@ export class NftStakingClient {
249
308
  })
250
309
  .instruction();
251
310
  }
252
- async createStakePool(projectId, stakingMode, rewardConfig, lockConfigs, collectionMint, rewardEndAt = 0, maxStaked = 0) {
253
- const config = await this.fetchStakeConfig(projectId);
311
+ async createStakePool(stakingMode, rewardConfig, lockConfigs, collectionMint, opts) {
312
+ const _collMint = toPk(collectionMint);
313
+ const _rewardMint = toPk(rewardConfig.rewardMint);
314
+ const pid = this.resolveProjectId(opts?.projectId);
315
+ const rewardEndAt = opts?.rewardEndAt ?? 0;
316
+ const maxStaked = opts?.maxStaked ?? 0;
317
+ const config = await this.fetchStakeConfig(pid);
254
318
  const nextPoolId = config ? config.totalPools : 0;
255
- const tokenProgram = await this.resolveTokenProgram(rewardConfig.rewardMint);
256
- const decimals = await this.getMintDecimals(rewardConfig.rewardMint);
319
+ const tokenProgram = await this.resolveTokenProgram(_rewardMint);
320
+ const decimals = await this.getMintDecimals(_rewardMint);
257
321
  const multiplier = 10 ** decimals;
258
322
  const rawRewardConfig = {
259
323
  rewardType: rewardConfig.rewardType,
260
- rewardMint: rewardConfig.rewardMint,
324
+ rewardMint: _rewardMint,
261
325
  baseRate: new BN(Math.round(rewardConfig.baseRate * multiplier)),
262
326
  rateInterval: new BN(rewardConfig.rateInterval),
263
327
  traitBonusMode: rewardConfig.traitBonusMode,
@@ -268,21 +332,23 @@ export class NftStakingClient {
268
332
  rewardRate: new BN(Math.round(lc.rewardRate * multiplier)),
269
333
  earlyUnstakePenaltyBps: lc.earlyUnstakePenaltyBps,
270
334
  }));
271
- const [configPda] = getStakeConfigPda(projectId);
272
- const [poolPda] = getStakePoolPda(projectId, nextPoolId);
273
- const [collectionConfigPda] = getCollectionPda(projectId, collectionMint);
335
+ const [configPda] = getStakeConfigPda(pid);
336
+ const [poolPda] = getStakePoolPda(pid, nextPoolId);
337
+ const [collectionConfigPda] = getCollectionPda(pid, _collMint);
274
338
  const [poolAuthority] = getPoolAuthorityPda(nextPoolId);
275
- const rewardVault = getAta(poolAuthority, rewardConfig.rewardMint, tokenProgram);
339
+ const rewardVault = getAta(poolAuthority, _rewardMint, tokenProgram);
340
+ const [utilityConfig] = getUtilityConfigPda(pid, this.program.programId);
276
341
  return this.program.methods
277
- .createStakePool(new BN(projectId), stakingMode, rawRewardConfig, rawLockConfigs, new BN(rewardEndAt), new BN(maxStaked))
342
+ .createStakePool(new BN(pid), stakingMode, rawRewardConfig, rawLockConfigs, new BN(rewardEndAt), new BN(maxStaked))
278
343
  .accountsStrict({
279
344
  config: configPda,
280
345
  pool: poolPda,
281
346
  collectionConfig: collectionConfigPda,
282
347
  poolAuthority,
283
- collectionMint,
284
- rewardMint: rewardConfig.rewardMint,
348
+ collectionMint: _collMint,
349
+ rewardMint: _rewardMint,
285
350
  rewardVault,
351
+ utilityConfig,
286
352
  projectManagementProgram: PROJECT_MANAGEMENT_PROGRAM_ID,
287
353
  authority: this.provider.wallet.publicKey,
288
354
  tokenProgram,
@@ -291,15 +357,26 @@ export class NftStakingClient {
291
357
  })
292
358
  .instruction();
293
359
  }
294
- async updateStakePool(projectId, poolId, rewardConfig, lockConfigs, isActive, traitAuthority = null, canBurn = null, merkleRoot = null, gateType = null, rewardEndAt = null, maxStaked = null) {
360
+ async updateStakePool(poolId, updates = {}) {
361
+ const pid = this.resolveProjectId(updates.projectId);
362
+ const rewardConfig = updates.rewardConfig ?? null;
363
+ const lockConfigs = updates.lockConfigs ?? null;
364
+ const isActive = updates.isActive ?? null;
365
+ const traitAuthority = updates.traitAuthority != null ? toPk(updates.traitAuthority) : null;
366
+ const canBurn = updates.canBurn ?? null;
367
+ const merkleRoot = updates.merkleRoot ?? null;
368
+ const gateType = updates.gateType ?? null;
369
+ const rewardEndAt = updates.rewardEndAt != null ? new BN(updates.rewardEndAt) : null;
370
+ const maxStaked = updates.maxStaked != null ? new BN(updates.maxStaked) : null;
295
371
  let rawRewardConfig = null;
296
372
  let rawLockConfigs = null;
297
373
  if (rewardConfig) {
298
- const decimals = await this.getMintDecimals(rewardConfig.rewardMint);
374
+ const _rMint = toPk(rewardConfig.rewardMint);
375
+ const decimals = await this.getMintDecimals(_rMint);
299
376
  const multiplier = 10 ** decimals;
300
377
  rawRewardConfig = {
301
378
  rewardType: rewardConfig.rewardType,
302
- rewardMint: rewardConfig.rewardMint,
379
+ rewardMint: _rMint,
303
380
  baseRate: new BN(Math.round(rewardConfig.baseRate * multiplier)),
304
381
  rateInterval: new BN(rewardConfig.rateInterval),
305
382
  traitBonusMode: rewardConfig.traitBonusMode,
@@ -307,7 +384,7 @@ export class NftStakingClient {
307
384
  };
308
385
  }
309
386
  if (lockConfigs && rewardConfig) {
310
- const decimals = await this.getMintDecimals(rewardConfig.rewardMint);
387
+ const decimals = await this.getMintDecimals(toPk(rewardConfig.rewardMint));
311
388
  const multiplier = 10 ** decimals;
312
389
  rawLockConfigs = lockConfigs.map((lc) => ({
313
390
  lockDuration: new BN(lc.lockDuration),
@@ -316,7 +393,7 @@ export class NftStakingClient {
316
393
  }));
317
394
  }
318
395
  else if (lockConfigs) {
319
- const pool = await this.fetchStakePool(projectId, poolId);
396
+ const pool = await this.fetchStakePool(pid, poolId);
320
397
  const decimals = pool ? pool.rewardDecimals : 0;
321
398
  const multiplier = 10 ** decimals;
322
399
  rawLockConfigs = lockConfigs.map((lc) => ({
@@ -325,23 +402,27 @@ export class NftStakingClient {
325
402
  earlyUnstakePenaltyBps: lc.earlyUnstakePenaltyBps,
326
403
  }));
327
404
  }
328
- const [poolPda] = getStakePoolPda(projectId, poolId);
405
+ const [poolPda] = getStakePoolPda(pid, poolId);
329
406
  return this.program.methods
330
- .updateStakePool(new BN(projectId), new BN(poolId), rawRewardConfig, rawLockConfigs, isActive, traitAuthority, canBurn, merkleRoot, gateType, rewardEndAt, maxStaked)
407
+ .updateStakePool(new BN(pid), new BN(poolId), rawRewardConfig, rawLockConfigs, isActive, traitAuthority, canBurn, merkleRoot, gateType, rewardEndAt, maxStaked)
331
408
  .accountsStrict({
332
409
  pool: poolPda,
333
410
  authority: this.provider.wallet.publicKey,
334
411
  })
335
412
  .instruction();
336
413
  }
337
- async fundRewardVault(projectId, poolId, amount, rewardMint, funderTokenAccount) {
414
+ /** Fund the primary reward vault. Auto-resolves rewardMint from pool if not provided. */
415
+ async fundRewardVault(poolId, amount, opts) {
416
+ const pid = this.resolveProjectId(opts?.projectId);
417
+ const pool = await this.getPoolData(pid, poolId);
418
+ const rewardMint = opts?.rewardMint ? toPk(opts.rewardMint) : new PublicKey(pool.rewardConfig.rewardMint);
338
419
  const tokenProgram = await this.resolveTokenProgram(rewardMint);
339
- const [poolPda] = getStakePoolPda(projectId, poolId);
420
+ const [poolPda] = getStakePoolPda(pid, poolId);
340
421
  const [poolAuthority] = getPoolAuthorityPda(poolId);
341
422
  const rewardVault = getAta(poolAuthority, rewardMint, tokenProgram);
342
- const funderAta = funderTokenAccount ?? getAta(this.provider.wallet.publicKey, rewardMint, tokenProgram);
423
+ const funderAta = opts?.funderTokenAccount ? toPk(opts.funderTokenAccount) : getAta(this.provider.wallet.publicKey, rewardMint, tokenProgram);
343
424
  return this.program.methods
344
- .fundRewardVault(new BN(projectId), new BN(poolId), amount)
425
+ .fundRewardVault(new BN(pid), new BN(poolId), toBN(amount))
345
426
  .accountsStrict({
346
427
  pool: poolPda,
347
428
  poolAuthority,
@@ -353,14 +434,18 @@ export class NftStakingClient {
353
434
  })
354
435
  .instruction();
355
436
  }
356
- async withdrawRewardVault(projectId, poolId, amount, rewardMint, destinationTokenAccount) {
437
+ /** Withdraw from the primary reward vault. Auto-resolves rewardMint from pool if not provided. */
438
+ async withdrawRewardVault(poolId, amount, opts) {
439
+ const pid = this.resolveProjectId(opts?.projectId);
440
+ const pool = await this.getPoolData(pid, poolId);
441
+ const rewardMint = opts?.rewardMint ? toPk(opts.rewardMint) : new PublicKey(pool.rewardConfig.rewardMint);
357
442
  const tokenProgram = await this.resolveTokenProgram(rewardMint);
358
- const [poolPda] = getStakePoolPda(projectId, poolId);
443
+ const [poolPda] = getStakePoolPda(pid, poolId);
359
444
  const [poolAuthority] = getPoolAuthorityPda(poolId);
360
445
  const rewardVault = getAta(poolAuthority, rewardMint, tokenProgram);
361
- const destAta = destinationTokenAccount ?? getAta(this.provider.wallet.publicKey, rewardMint, tokenProgram);
446
+ const destAta = opts?.destinationTokenAccount ? toPk(opts.destinationTokenAccount) : getAta(this.provider.wallet.publicKey, rewardMint, tokenProgram);
362
447
  return this.program.methods
363
- .withdrawRewardVault(new BN(projectId), new BN(poolId), amount)
448
+ .withdrawRewardVault(new BN(pid), new BN(poolId), toBN(amount))
364
449
  .accountsStrict({
365
450
  pool: poolPda,
366
451
  poolAuthority,
@@ -372,50 +457,67 @@ export class NftStakingClient {
372
457
  })
373
458
  .instruction();
374
459
  }
375
- async closeStakePool(projectId, poolId) {
376
- const [poolPda] = getStakePoolPda(projectId, poolId);
460
+ async closeStakePool(poolId, projectId) {
461
+ const pid = this.resolveProjectId(projectId);
462
+ const [poolPda] = getStakePoolPda(pid, poolId);
377
463
  return this.program.methods
378
- .closeStakePool(new BN(projectId), new BN(poolId))
464
+ .closeStakePool(new BN(pid), new BN(poolId))
379
465
  .accountsStrict({
380
466
  pool: poolPda,
467
+ rewardVault: null,
468
+ tokenProgram: null,
381
469
  authority: this.provider.wallet.publicKey,
382
470
  })
383
471
  .instruction();
384
472
  }
385
- async stakeNft(projectId, poolId, nftMint, stakingMode, lockTierIndex, fee, gateProof = []) {
386
- const [poolPda] = getStakePoolPda(projectId, poolId);
387
- const [stakeEntry] = getStakeEntryPda(poolId, nftMint);
473
+ /** Stake a legacy/pNFT. Auto-resolves stakingMode from pool. */
474
+ async stakeNft(poolId, nftMint, opts) {
475
+ const _nftMint = toPk(nftMint);
476
+ const pid = this.resolveProjectId(opts?.projectId);
477
+ const pool = await this.getPoolData(pid, poolId);
478
+ const stakingMode = pool.stakingMode;
479
+ const lockTierIndex = opts?.lockTierIndex ?? null;
480
+ const gateProof = opts?.gateProof ?? [];
481
+ const [poolPda] = getStakePoolPda(pid, poolId);
482
+ const [stakeEntry] = getStakeEntryPda(poolId, _nftMint);
388
483
  const staker = this.provider.wallet.publicKey;
389
484
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
390
485
  const [poolAuthority] = getPoolAuthorityPda(poolId);
391
- const nftTokenProgram = await this.resolveTokenProgram(nftMint);
392
- const stakerNftAccount = getAta(staker, nftMint, nftTokenProgram);
486
+ const nftTokenProgram = await this.resolveTokenProgram(_nftMint);
487
+ const stakerNftAccount = getAta(staker, _nftMint, nftTokenProgram);
393
488
  const isEscrow = stakingMode !== 1;
394
489
  const escrowNftAccount = isEscrow
395
- ? getAta(poolAuthority, nftMint, nftTokenProgram)
490
+ ? getAta(poolAuthority, _nftMint, nftTokenProgram)
396
491
  : null;
397
- const nftMetadata = getMetadataPda(nftMint);
398
- const nftEdition = getEditionPda(nftMint);
399
- const feeAccts = this.resolveFeeAccounts(fee);
492
+ const nftMetadata = getMetadataPda(_nftMint);
493
+ const nftEdition = getEditionPda(_nftMint);
494
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
495
+ const [project] = getProjectPda(pid);
496
+ const [utilityConfig] = getUtilityConfigPda(pid, this.program.programId);
400
497
  return this.program.methods
401
- .stakeNft(new BN(projectId), new BN(poolId), nftMint, lockTierIndex, gateProof)
498
+ .stakeNft(new BN(pid), new BN(poolId), _nftMint, lockTierIndex, gateProof)
402
499
  .accountsStrict({
403
500
  pool: poolPda,
404
501
  stakeEntry,
405
502
  stakerAccount,
406
503
  poolAuthority,
407
- nftMint,
504
+ nftMint: _nftMint,
408
505
  stakerNftAccount,
409
506
  escrowNftAccount,
410
507
  nftMetadata,
411
508
  nftEdition,
412
509
  mplTokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
413
510
  sysvarInstructions: SYSVAR_INSTRUCTIONS_ID,
511
+ tokenRecord: null,
512
+ destinationTokenRecord: null,
513
+ utilityConfig,
414
514
  feeConfig: feeAccts.feeConfig,
515
+ programRegistry: feeAccts.programRegistry,
415
516
  treasury: feeAccts.treasury,
416
517
  referralAccount: feeAccts.referralAccount,
417
518
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
418
519
  adminProgram: feeAccts.adminProgram,
520
+ project,
419
521
  staker,
420
522
  tokenProgram: nftTokenProgram,
421
523
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
@@ -423,32 +525,37 @@ export class NftStakingClient {
423
525
  })
424
526
  .instruction();
425
527
  }
426
- async unstakeNft(projectId, poolId, nftMint, rewardMint, stakingMode, fee) {
528
+ /** Unstake a legacy/pNFT. Auto-resolves rewardMint and stakingMode from pool. */
529
+ async unstakeNft(poolId, nftMint, opts) {
530
+ const _nftMint = toPk(nftMint);
531
+ const pid = this.resolveProjectId(opts?.projectId);
532
+ const pool = await this.getPoolData(pid, poolId);
533
+ const rewardMint = new PublicKey(pool.rewardConfig.rewardMint);
534
+ const stakingMode = pool.stakingMode;
427
535
  const rewardTokenProgram = await this.resolveTokenProgram(rewardMint);
428
- const nftTokenProgram = await this.resolveTokenProgram(nftMint);
429
- const [poolPda] = getStakePoolPda(projectId, poolId);
430
- const [stakeEntry] = getStakeEntryPda(poolId, nftMint);
536
+ const nftTokenProgram = await this.resolveTokenProgram(_nftMint);
537
+ const [poolPda] = getStakePoolPda(pid, poolId);
538
+ const [stakeEntry] = getStakeEntryPda(poolId, _nftMint);
431
539
  const staker = this.provider.wallet.publicKey;
432
540
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
433
541
  const [poolAuthority] = getPoolAuthorityPda(poolId);
434
- const stakerNftAccount = getAta(staker, nftMint, nftTokenProgram);
542
+ const stakerNftAccount = getAta(staker, _nftMint, nftTokenProgram);
435
543
  const isEscrow = stakingMode !== 1;
436
544
  const escrowNftAccount = isEscrow
437
- ? getAta(poolAuthority, nftMint, nftTokenProgram)
545
+ ? getAta(poolAuthority, _nftMint, nftTokenProgram)
438
546
  : null;
439
547
  const rewardVault = getAta(poolAuthority, rewardMint, rewardTokenProgram);
440
548
  const stakerRewardAccount = getAta(staker, rewardMint, rewardTokenProgram);
441
- const nftMetadata = getMetadataPda(nftMint);
442
- const nftEdition = getEditionPda(nftMint);
443
- const feeAccts = this.resolveFeeAccounts(fee);
549
+ const nftMetadata = getMetadataPda(_nftMint);
550
+ const nftEdition = getEditionPda(_nftMint);
444
551
  return this.program.methods
445
- .unstakeNft(new BN(projectId), new BN(poolId), nftMint)
552
+ .unstakeNft(new BN(pid), new BN(poolId), _nftMint)
446
553
  .accountsStrict({
447
554
  pool: poolPda,
448
555
  stakeEntry,
449
556
  stakerAccount,
450
557
  poolAuthority,
451
- nftMint,
558
+ nftMint: _nftMint,
452
559
  stakerNftAccount,
453
560
  escrowNftAccount,
454
561
  rewardVault,
@@ -458,11 +565,8 @@ export class NftStakingClient {
458
565
  nftEdition,
459
566
  mplTokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
460
567
  sysvarInstructions: SYSVAR_INSTRUCTIONS_ID,
461
- feeConfig: feeAccts.feeConfig,
462
- treasury: feeAccts.treasury,
463
- referralAccount: feeAccts.referralAccount,
464
- solUsdPriceFeed: feeAccts.solUsdPriceFeed,
465
- adminProgram: feeAccts.adminProgram,
568
+ tokenRecord: null,
569
+ destinationTokenRecord: null,
466
570
  staker,
467
571
  tokenProgram: nftTokenProgram,
468
572
  rewardTokenProgram,
@@ -471,18 +575,24 @@ export class NftStakingClient {
471
575
  })
472
576
  .instruction();
473
577
  }
474
- async claimRewards(projectId, poolId, rewardMint, traitBonusRate = null, fee) {
578
+ /** Claim accrued rewards. Auto-resolves rewardMint from pool. */
579
+ async claimRewards(poolId, opts) {
580
+ const pid = this.resolveProjectId(opts?.projectId);
581
+ const pool = await this.getPoolData(pid, poolId);
582
+ const rewardMint = new PublicKey(pool.rewardConfig.rewardMint);
583
+ const traitBonusRate = opts?.traitBonusRate ?? null;
475
584
  const tokenProgram = await this.resolveTokenProgram(rewardMint);
476
- const [poolPda] = getStakePoolPda(projectId, poolId);
585
+ const [poolPda] = getStakePoolPda(pid, poolId);
477
586
  const staker = this.provider.wallet.publicKey;
478
587
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
479
588
  const [poolAuthority] = getPoolAuthorityPda(poolId);
480
589
  const rewardVault = getAta(poolAuthority, rewardMint, tokenProgram);
481
590
  const stakerRewardAccount = getAta(staker, rewardMint, tokenProgram);
482
- const [stakeConfig] = getStakeConfigPda(projectId);
483
- const feeAccts = this.resolveFeeAccounts(fee);
591
+ const [stakeConfig] = getStakeConfigPda(pid);
592
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
593
+ const [project] = getProjectPda(pid);
484
594
  return this.program.methods
485
- .claimRewards(new BN(projectId), new BN(poolId), traitBonusRate)
595
+ .claimRewards(new BN(pid), new BN(poolId), traitBonusRate)
486
596
  .accountsStrict({
487
597
  pool: poolPda,
488
598
  stakerAccount,
@@ -493,10 +603,12 @@ export class NftStakingClient {
493
603
  stakeConfig,
494
604
  instructionsSysvar: new PublicKey("Sysvar1nstructions1111111111111111111111111"),
495
605
  feeConfig: feeAccts.feeConfig,
606
+ programRegistry: feeAccts.programRegistry,
496
607
  treasury: feeAccts.treasury,
497
608
  referralAccount: feeAccts.referralAccount,
498
609
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
499
610
  adminProgram: feeAccts.adminProgram,
611
+ project,
500
612
  staker,
501
613
  tokenProgram,
502
614
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
@@ -504,61 +616,73 @@ export class NftStakingClient {
504
616
  })
505
617
  .instruction();
506
618
  }
507
- async stakeCoreNft(projectId, poolId, nftAsset, collection, lockTierIndex, fee, gateProof = []) {
508
- const [poolPda] = getStakePoolPda(projectId, poolId);
509
- const [stakeEntry] = getStakeEntryPda(poolId, nftAsset);
619
+ /** Stake a Core NFT. Auto-resolves collection from pool. */
620
+ async stakeCoreNft(poolId, nftAsset, opts) {
621
+ const _nftAsset = toPk(nftAsset);
622
+ const pid = this.resolveProjectId(opts?.projectId);
623
+ const pool = await this.getPoolData(pid, poolId);
624
+ const collection = new PublicKey(pool.collectionMint);
625
+ const lockTierIndex = opts?.lockTierIndex ?? null;
626
+ const gateProof = opts?.gateProof ?? [];
627
+ const [poolPda] = getStakePoolPda(pid, poolId);
628
+ const [stakeEntry] = getStakeEntryPda(poolId, _nftAsset);
510
629
  const staker = this.provider.wallet.publicKey;
511
630
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
512
631
  const [poolAuthority] = getPoolAuthorityPda(poolId);
513
- const feeAccts = this.resolveFeeAccounts(fee);
632
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
633
+ const [project] = getProjectPda(pid);
634
+ const [utilityConfig] = getUtilityConfigPda(pid, this.program.programId);
514
635
  return this.program.methods
515
- .stakeCoreNft(new BN(projectId), new BN(poolId), nftAsset, lockTierIndex, gateProof)
636
+ .stakeCoreNft(new BN(pid), new BN(poolId), _nftAsset, lockTierIndex, gateProof)
516
637
  .accountsStrict({
517
638
  pool: poolPda,
518
639
  stakeEntry,
519
640
  stakerAccount,
520
641
  poolAuthority,
521
- nftAsset,
642
+ nftAsset: _nftAsset,
522
643
  collection,
523
644
  mplCoreProgram: MPL_CORE_PROGRAM_ID,
645
+ utilityConfig,
524
646
  feeConfig: feeAccts.feeConfig,
647
+ programRegistry: feeAccts.programRegistry,
525
648
  treasury: feeAccts.treasury,
526
649
  referralAccount: feeAccts.referralAccount,
527
650
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
528
651
  adminProgram: feeAccts.adminProgram,
652
+ project,
529
653
  staker,
530
654
  systemProgram: SystemProgram.programId,
531
655
  })
532
656
  .instruction();
533
657
  }
534
- async unstakeCoreNft(projectId, poolId, nftAsset, collection, rewardMint, fee) {
658
+ /** Unstake a Core NFT. Auto-resolves collection and rewardMint from pool. */
659
+ async unstakeCoreNft(poolId, nftAsset, opts) {
660
+ const _nftAsset = toPk(nftAsset);
661
+ const pid = this.resolveProjectId(opts?.projectId);
662
+ const pool = await this.getPoolData(pid, poolId);
663
+ const collection = new PublicKey(pool.collectionMint);
664
+ const rewardMint = new PublicKey(pool.rewardConfig.rewardMint);
535
665
  const rewardTokenProgram = await this.resolveTokenProgram(rewardMint);
536
- const [poolPda] = getStakePoolPda(projectId, poolId);
537
- const [stakeEntry] = getStakeEntryPda(poolId, nftAsset);
666
+ const [poolPda] = getStakePoolPda(pid, poolId);
667
+ const [stakeEntry] = getStakeEntryPda(poolId, _nftAsset);
538
668
  const staker = this.provider.wallet.publicKey;
539
669
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
540
670
  const [poolAuthority] = getPoolAuthorityPda(poolId);
541
671
  const rewardVault = getAta(poolAuthority, rewardMint, rewardTokenProgram);
542
672
  const stakerRewardAccount = getAta(staker, rewardMint, rewardTokenProgram);
543
- const feeAccts = this.resolveFeeAccounts(fee);
544
673
  return this.program.methods
545
- .unstakeCoreNft(new BN(projectId), new BN(poolId), nftAsset)
674
+ .unstakeCoreNft(new BN(pid), new BN(poolId), _nftAsset)
546
675
  .accountsStrict({
547
676
  pool: poolPda,
548
677
  stakeEntry,
549
678
  stakerAccount,
550
679
  poolAuthority,
551
- nftAsset,
680
+ nftAsset: _nftAsset,
552
681
  collection,
553
682
  mplCoreProgram: MPL_CORE_PROGRAM_ID,
554
683
  rewardVault,
555
684
  stakerRewardAccount,
556
685
  rewardMint,
557
- feeConfig: feeAccts.feeConfig,
558
- treasury: feeAccts.treasury,
559
- referralAccount: feeAccts.referralAccount,
560
- solUsdPriceFeed: feeAccts.solUsdPriceFeed,
561
- adminProgram: feeAccts.adminProgram,
562
686
  staker,
563
687
  rewardTokenProgram,
564
688
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
@@ -567,26 +691,31 @@ export class NftStakingClient {
567
691
  .instruction();
568
692
  }
569
693
  /** Stake a compressed NFT (cNFT). All address/hash params accepted as strings. */
570
- async stakeCnft(projectId, poolId, nftAssetId, merkleTree, cnftRoot, cnftDataHash, cnftCreatorHash, cnftNonce, cnftIndex, proofNodes, fee, gateProof = []) {
694
+ async stakeCnft(poolId, cnftParams, opts) {
695
+ const pid = this.resolveProjectId(opts?.projectId);
696
+ const gateProof = opts?.gateProof ?? [];
697
+ const { nftAssetId, merkleTree, cnftRoot, cnftDataHash, cnftCreatorHash, cnftNonce, cnftIndex, proofNodes } = cnftParams;
571
698
  const nftAssetIdPk = new PublicKey(nftAssetId);
572
699
  const merkleTreePk = new PublicKey(merkleTree);
573
700
  const [treeConfigPk] = getTreeConfigPda(merkleTreePk);
574
701
  const cnftRootArr = base58HashToArray(cnftRoot);
575
702
  const cnftDataHashArr = base58HashToArray(cnftDataHash);
576
703
  const cnftCreatorHashArr = base58HashToArray(cnftCreatorHash);
577
- const [poolPda] = getStakePoolPda(projectId, poolId);
704
+ const [poolPda] = getStakePoolPda(pid, poolId);
578
705
  const [stakeEntry] = getStakeEntryPda(poolId, nftAssetIdPk);
579
706
  const staker = this.provider.wallet.publicKey;
580
707
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
581
708
  const [poolAuthority] = getPoolAuthorityPda(poolId);
582
- const feeAccts = this.resolveFeeAccounts(fee);
709
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
710
+ const [project] = getProjectPda(pid);
711
+ const [utilityConfig] = getUtilityConfigPda(pid, this.program.programId);
583
712
  const remainingAccounts = proofNodes.map((node) => ({
584
713
  pubkey: new PublicKey(node),
585
714
  isSigner: false,
586
715
  isWritable: false,
587
716
  }));
588
717
  return this.program.methods
589
- .stakeCnft(new BN(projectId), new BN(poolId), nftAssetIdPk, cnftRootArr, cnftDataHashArr, cnftCreatorHashArr, new BN(cnftNonce), cnftIndex, gateProof)
718
+ .stakeCnft(new BN(pid), new BN(poolId), nftAssetIdPk, cnftRootArr, cnftDataHashArr, cnftCreatorHashArr, new BN(cnftNonce), cnftIndex, gateProof)
590
719
  .accountsStrict({
591
720
  pool: poolPda,
592
721
  stakeEntry,
@@ -597,32 +726,37 @@ export class NftStakingClient {
597
726
  logWrapper: SPL_NOOP_PROGRAM_ID,
598
727
  compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
599
728
  bubblegumProgram: BUBBLEGUM_PROGRAM_ID,
729
+ utilityConfig,
600
730
  feeConfig: feeAccts.feeConfig,
731
+ programRegistry: feeAccts.programRegistry,
601
732
  treasury: feeAccts.treasury,
602
733
  referralAccount: feeAccts.referralAccount,
603
734
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
604
735
  adminProgram: feeAccts.adminProgram,
736
+ project,
605
737
  staker,
606
738
  systemProgram: SystemProgram.programId,
607
739
  })
608
740
  .remainingAccounts(remainingAccounts)
609
741
  .instruction();
610
742
  }
611
- /** Unstake a compressed NFT (cNFT). Derives tree config and program IDs internally. */
612
- async unstakeCnft(projectId, poolId, nftAssetId, merkleTree, rewardMint, cnftRoot, cnftDataHash, cnftCreatorHash, cnftNonce, cnftIndex, proofNodes, fee) {
743
+ /** Unstake a compressed NFT (cNFT). Auto-resolves rewardMint from pool. */
744
+ async unstakeCnft(poolId, cnftParams, opts) {
745
+ const pid = this.resolveProjectId(opts?.projectId);
746
+ const pool = await this.getPoolData(pid, poolId);
747
+ const { nftAssetId, merkleTree, cnftRoot, cnftDataHash, cnftCreatorHash, cnftNonce, cnftIndex, proofNodes } = cnftParams;
613
748
  const nftAssetIdPk = new PublicKey(nftAssetId);
614
749
  const merkleTreePk = new PublicKey(merkleTree);
615
750
  const [treeConfigPk] = getTreeConfigPda(merkleTreePk);
616
- const rewardMintPk = new PublicKey(rewardMint);
751
+ const rewardMintPk = new PublicKey(pool.rewardConfig.rewardMint);
617
752
  const cnftRootArr = base58HashToArray(cnftRoot);
618
753
  const cnftDataHashArr = base58HashToArray(cnftDataHash);
619
754
  const cnftCreatorHashArr = base58HashToArray(cnftCreatorHash);
620
- const [poolPda] = getStakePoolPda(projectId, poolId);
755
+ const [poolPda] = getStakePoolPda(pid, poolId);
621
756
  const [stakeEntry] = getStakeEntryPda(poolId, nftAssetIdPk);
622
757
  const staker = this.provider.wallet.publicKey;
623
758
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
624
759
  const [poolAuthority] = getPoolAuthorityPda(poolId);
625
- const feeAccts = this.resolveFeeAccounts(fee);
626
760
  const rewardVaultPk = getAta(poolAuthority, rewardMintPk);
627
761
  const stakerRewardAccountPk = getAta(staker, rewardMintPk);
628
762
  const remainingAccounts = proofNodes.map((node) => ({
@@ -631,7 +765,7 @@ export class NftStakingClient {
631
765
  isWritable: false,
632
766
  }));
633
767
  return this.program.methods
634
- .unstakeCnft(new BN(projectId), new BN(poolId), nftAssetIdPk, cnftRootArr, cnftDataHashArr, cnftCreatorHashArr, new BN(cnftNonce), cnftIndex)
768
+ .unstakeCnft(new BN(pid), new BN(poolId), nftAssetIdPk, cnftRootArr, cnftDataHashArr, cnftCreatorHashArr, new BN(cnftNonce), cnftIndex)
635
769
  .accountsStrict({
636
770
  pool: poolPda,
637
771
  stakeEntry,
@@ -645,11 +779,6 @@ export class NftStakingClient {
645
779
  rewardVault: rewardVaultPk,
646
780
  stakerRewardAccount: stakerRewardAccountPk,
647
781
  rewardMint: rewardMintPk,
648
- feeConfig: feeAccts.feeConfig,
649
- treasury: feeAccts.treasury,
650
- referralAccount: feeAccts.referralAccount,
651
- solUsdPriceFeed: feeAccts.solUsdPriceFeed,
652
- adminProgram: feeAccts.adminProgram,
653
782
  staker,
654
783
  tokenProgram: TOKEN_PROGRAM_ID,
655
784
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
@@ -658,90 +787,109 @@ export class NftStakingClient {
658
787
  .remainingAccounts(remainingAccounts)
659
788
  .instruction();
660
789
  }
661
- /** Burn a permanently-locked legacy/pNFT. Destroys the NFT and closes the stake entry.
662
- * For Escrow mode, burns from escrow. For WalletLock, unfreezes then burns from wallet. */
663
- async burnStakedNft(projectId, poolId, nftMint, stakingMode, fee) {
664
- const nftTokenProgram = await this.resolveTokenProgram(nftMint);
665
- const [poolPda] = getStakePoolPda(projectId, poolId);
666
- const [stakeEntry] = getStakeEntryPda(poolId, nftMint);
790
+ /** Burn a permanently-locked legacy/pNFT. Auto-resolves stakingMode from pool. */
791
+ async burnStakedNft(poolId, nftMint, opts) {
792
+ const _nftMint = toPk(nftMint);
793
+ const pid = this.resolveProjectId(opts?.projectId);
794
+ const pool = await this.getPoolData(pid, poolId);
795
+ const stakingMode = pool.stakingMode;
796
+ const nftTokenProgram = await this.resolveTokenProgram(_nftMint);
797
+ const [poolPda] = getStakePoolPda(pid, poolId);
798
+ const [stakeEntry] = getStakeEntryPda(poolId, _nftMint);
667
799
  const staker = this.provider.wallet.publicKey;
668
800
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
669
801
  const [poolAuthority] = getPoolAuthorityPda(poolId);
670
- const feeAccts = this.resolveFeeAccounts(fee);
802
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
803
+ const [project] = getProjectPda(pid);
671
804
  const isWalletLock = stakingMode === 1;
672
- const escrowNftAccount = isWalletLock ? null : getAta(poolAuthority, nftMint, nftTokenProgram);
673
- const stakerNftAccount = isWalletLock ? getAta(staker, nftMint, nftTokenProgram) : null;
674
- const nftMetadata = isWalletLock ? getMetadataPda(nftMint) : null;
675
- const nftEdition = isWalletLock ? getEditionPda(nftMint) : null;
805
+ const escrowNftAccount = isWalletLock ? null : getAta(poolAuthority, _nftMint, nftTokenProgram);
806
+ const stakerNftAccount = isWalletLock ? getAta(staker, _nftMint, nftTokenProgram) : null;
807
+ const nftMetadata = isWalletLock ? getMetadataPda(_nftMint) : null;
808
+ const nftEdition = isWalletLock ? getEditionPda(_nftMint) : null;
676
809
  return this.program.methods
677
- .burnStakedNft(new BN(projectId), new BN(poolId), nftMint)
810
+ .burnStakedNft(new BN(pid), new BN(poolId), _nftMint)
678
811
  .accountsStrict({
679
812
  pool: poolPda,
680
813
  stakeEntry,
681
814
  stakerAccount,
682
815
  poolAuthority,
683
- nftMint,
816
+ nftMint: _nftMint,
684
817
  escrowNftAccount,
685
818
  stakerNftAccount,
686
819
  nftMetadata,
687
820
  nftEdition,
688
821
  mplTokenMetadataProgram: isWalletLock ? TOKEN_METADATA_PROGRAM_ID : null,
689
822
  sysvarInstructions: isWalletLock ? SYSVAR_INSTRUCTIONS_ID : null,
823
+ tokenRecord: null,
824
+ collectionMetadata: null,
690
825
  feeConfig: feeAccts.feeConfig,
826
+ programRegistry: feeAccts.programRegistry,
691
827
  treasury: feeAccts.treasury,
692
828
  referralAccount: feeAccts.referralAccount,
693
829
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
694
830
  adminProgram: feeAccts.adminProgram,
831
+ project,
695
832
  staker,
696
833
  tokenProgram: nftTokenProgram,
697
834
  systemProgram: SystemProgram.programId,
698
835
  })
699
836
  .instruction();
700
837
  }
701
- /** Burn a permanently-locked Core NFT. Destroys the asset and closes the stake entry. */
702
- async burnStakedCoreNft(projectId, poolId, nftAsset, collection, fee) {
703
- const [poolPda] = getStakePoolPda(projectId, poolId);
704
- const [stakeEntry] = getStakeEntryPda(poolId, nftAsset);
838
+ /** Burn a permanently-locked Core NFT. Auto-resolves collection from pool. */
839
+ async burnStakedCoreNft(poolId, nftAsset, opts) {
840
+ const _nftAsset = toPk(nftAsset);
841
+ const pid = this.resolveProjectId(opts?.projectId);
842
+ const pool = await this.getPoolData(pid, poolId);
843
+ const collection = new PublicKey(pool.collectionMint);
844
+ const [poolPda] = getStakePoolPda(pid, poolId);
845
+ const [stakeEntry] = getStakeEntryPda(poolId, _nftAsset);
705
846
  const staker = this.provider.wallet.publicKey;
706
847
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
707
848
  const [poolAuthority] = getPoolAuthorityPda(poolId);
708
- const feeAccts = this.resolveFeeAccounts(fee);
849
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
850
+ const [project] = getProjectPda(pid);
709
851
  return this.program.methods
710
- .burnStakedCoreNft(new BN(projectId), new BN(poolId), nftAsset)
852
+ .burnStakedCoreNft(new BN(pid), new BN(poolId), _nftAsset)
711
853
  .accountsStrict({
712
854
  pool: poolPda,
713
855
  stakeEntry,
714
856
  stakerAccount,
715
857
  poolAuthority,
716
- nftAsset,
858
+ nftAsset: _nftAsset,
717
859
  collection,
718
860
  mplCoreProgram: MPL_CORE_PROGRAM_ID,
719
861
  feeConfig: feeAccts.feeConfig,
862
+ programRegistry: feeAccts.programRegistry,
720
863
  treasury: feeAccts.treasury,
721
864
  referralAccount: feeAccts.referralAccount,
722
865
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
723
866
  adminProgram: feeAccts.adminProgram,
867
+ project,
724
868
  staker,
725
869
  systemProgram: SystemProgram.programId,
726
870
  })
727
871
  .instruction();
728
872
  }
729
873
  /** Spend accrued points from a Points reward type pool. */
730
- async spendPoints(projectId, poolId, amount, fee) {
731
- const [poolPda] = getStakePoolPda(projectId, poolId);
874
+ async spendPoints(poolId, amount, opts) {
875
+ const pid = this.resolveProjectId(opts?.projectId);
876
+ const [poolPda] = getStakePoolPda(pid, poolId);
732
877
  const staker = this.provider.wallet.publicKey;
733
878
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
734
- const feeAccts = this.resolveFeeAccounts(fee);
879
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
880
+ const [project] = getProjectPda(pid);
735
881
  return this.program.methods
736
- .spendPoints(new BN(projectId), new BN(poolId), amount)
882
+ .spendPoints(new BN(pid), new BN(poolId), toBN(amount))
737
883
  .accountsStrict({
738
884
  pool: poolPda,
739
885
  stakerAccount,
740
886
  feeConfig: feeAccts.feeConfig,
887
+ programRegistry: feeAccts.programRegistry,
741
888
  treasury: feeAccts.treasury,
742
889
  referralAccount: feeAccts.referralAccount,
743
890
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
744
891
  adminProgram: feeAccts.adminProgram,
892
+ project,
745
893
  staker,
746
894
  systemProgram: SystemProgram.programId,
747
895
  })
@@ -755,25 +903,27 @@ export class NftStakingClient {
755
903
  return decodeAccount(raw);
756
904
  }
757
905
  async fetchStakerSecondaryRewards(poolId, wallet) {
758
- const [pda] = getStakerSecondaryRewardsPda(poolId, wallet);
906
+ const [pda] = getStakerSecondaryRewardsPda(poolId, toPk(wallet));
759
907
  const raw = await this.program.account.stakerSecondaryRewards.fetchNullable(pda);
760
908
  if (!raw)
761
909
  return null;
762
910
  return decodeAccount(raw);
763
911
  }
764
- async addPoolSecondaryReward(projectId, poolId, rewardMint, baseRate, lockTierRates) {
765
- const [poolPda] = getStakePoolPda(projectId, poolId);
912
+ async addPoolSecondaryReward(poolId, rewardMint, baseRate, lockTierRates, projectId) {
913
+ const pid = this.resolveProjectId(projectId);
914
+ const _rewardMint = toPk(rewardMint);
915
+ const [poolPda] = getStakePoolPda(pid, poolId);
766
916
  const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
767
917
  const [poolAuthority] = getPoolAuthorityPda(poolId);
768
- const tokenProgram = await this.resolveTokenProgram(rewardMint);
769
- const vault = getAta(poolAuthority, rewardMint, tokenProgram);
918
+ const tokenProgram = await this.resolveTokenProgram(_rewardMint);
919
+ const vault = getAta(poolAuthority, _rewardMint, tokenProgram);
770
920
  return this.program.methods
771
- .addPoolSecondaryReward(new BN(projectId), new BN(poolId), baseRate, lockTierRates)
921
+ .addPoolSecondaryReward(new BN(pid), new BN(poolId), toBN(baseRate), lockTierRates.map(toBN))
772
922
  .accountsStrict({
773
923
  pool: poolPda,
774
924
  poolSecondary,
775
925
  poolAuthority,
776
- secondaryRewardMint: rewardMint,
926
+ secondaryRewardMint: _rewardMint,
777
927
  secondaryVault: vault,
778
928
  authority: this.provider.wallet.publicKey,
779
929
  tokenProgram,
@@ -782,11 +932,12 @@ export class NftStakingClient {
782
932
  })
783
933
  .instruction();
784
934
  }
785
- async removePoolSecondaryReward(projectId, poolId, rewardIndex) {
786
- const [poolPda] = getStakePoolPda(projectId, poolId);
935
+ async removePoolSecondaryReward(poolId, rewardIndex, projectId) {
936
+ const pid = this.resolveProjectId(projectId);
937
+ const [poolPda] = getStakePoolPda(pid, poolId);
787
938
  const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
788
939
  return this.program.methods
789
- .removePoolSecondaryReward(new BN(projectId), new BN(poolId), rewardIndex)
940
+ .removePoolSecondaryReward(new BN(pid), new BN(poolId), rewardIndex)
790
941
  .accountsStrict({
791
942
  pool: poolPda,
792
943
  poolSecondary,
@@ -794,55 +945,60 @@ export class NftStakingClient {
794
945
  })
795
946
  .instruction();
796
947
  }
797
- async fundSecondaryVault(projectId, poolId, rewardIndex, amount, rewardMint, funderTokenAccount) {
798
- const tokenProgram = await this.resolveTokenProgram(rewardMint);
799
- const [poolPda] = getStakePoolPda(projectId, poolId);
948
+ async fundSecondaryVault(poolId, rewardIndex, amount, rewardMint, opts) {
949
+ const pid = this.resolveProjectId(opts?.projectId);
950
+ const _rewardMint = toPk(rewardMint);
951
+ const tokenProgram = await this.resolveTokenProgram(_rewardMint);
952
+ const [poolPda] = getStakePoolPda(pid, poolId);
800
953
  const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
801
954
  const [poolAuthority] = getPoolAuthorityPda(poolId);
802
- const vault = getAta(poolAuthority, rewardMint, tokenProgram);
803
- const funderAta = funderTokenAccount ?? getAta(this.provider.wallet.publicKey, rewardMint, tokenProgram);
955
+ const vault = getAta(poolAuthority, _rewardMint, tokenProgram);
956
+ const funderAta = opts?.funderTokenAccount ? toPk(opts.funderTokenAccount) : getAta(this.provider.wallet.publicKey, _rewardMint, tokenProgram);
804
957
  return this.program.methods
805
- .fundSecondaryVault(new BN(projectId), new BN(poolId), rewardIndex, amount)
958
+ .fundSecondaryVault(new BN(pid), new BN(poolId), rewardIndex, toBN(amount))
806
959
  .accountsStrict({
807
960
  pool: poolPda,
808
961
  poolSecondary,
809
962
  poolAuthority,
810
963
  secondaryVault: vault,
811
964
  funderTokenAccount: funderAta,
812
- secondaryRewardMint: rewardMint,
965
+ secondaryRewardMint: _rewardMint,
813
966
  authority: this.provider.wallet.publicKey,
814
967
  tokenProgram,
815
968
  })
816
969
  .instruction();
817
970
  }
818
- async withdrawSecondaryVault(projectId, poolId, rewardIndex, amount, rewardMint, destinationTokenAccount) {
819
- const tokenProgram = await this.resolveTokenProgram(rewardMint);
820
- const [poolPda] = getStakePoolPda(projectId, poolId);
971
+ async withdrawSecondaryVault(poolId, rewardIndex, amount, rewardMint, opts) {
972
+ const pid = this.resolveProjectId(opts?.projectId);
973
+ const _rewardMint = toPk(rewardMint);
974
+ const tokenProgram = await this.resolveTokenProgram(_rewardMint);
975
+ const [poolPda] = getStakePoolPda(pid, poolId);
821
976
  const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
822
977
  const [poolAuthority] = getPoolAuthorityPda(poolId);
823
- const vault = getAta(poolAuthority, rewardMint, tokenProgram);
824
- const destAta = destinationTokenAccount ?? getAta(this.provider.wallet.publicKey, rewardMint, tokenProgram);
978
+ const vault = getAta(poolAuthority, _rewardMint, tokenProgram);
979
+ const destAta = opts?.destinationTokenAccount ? toPk(opts.destinationTokenAccount) : getAta(this.provider.wallet.publicKey, _rewardMint, tokenProgram);
825
980
  return this.program.methods
826
- .withdrawSecondaryVault(new BN(projectId), new BN(poolId), rewardIndex, amount)
981
+ .withdrawSecondaryVault(new BN(pid), new BN(poolId), rewardIndex, toBN(amount))
827
982
  .accountsStrict({
828
983
  pool: poolPda,
829
984
  poolSecondary,
830
985
  poolAuthority,
831
986
  secondaryVault: vault,
832
987
  destinationTokenAccount: destAta,
833
- secondaryRewardMint: rewardMint,
988
+ secondaryRewardMint: _rewardMint,
834
989
  authority: this.provider.wallet.publicKey,
835
990
  tokenProgram,
836
991
  })
837
992
  .instruction();
838
993
  }
839
- async initStakerSecondary(projectId, poolId) {
840
- const [poolPda] = getStakePoolPda(projectId, poolId);
994
+ async initStakerSecondary(poolId, projectId) {
995
+ const pid = this.resolveProjectId(projectId);
996
+ const [poolPda] = getStakePoolPda(pid, poolId);
841
997
  const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
842
998
  const staker = this.provider.wallet.publicKey;
843
999
  const [stakerSecondary] = getStakerSecondaryRewardsPda(poolId, staker);
844
1000
  return this.program.methods
845
- .initStakerSecondary(new BN(projectId), new BN(poolId))
1001
+ .initStakerSecondary(new BN(pid), new BN(poolId))
846
1002
  .accountsStrict({
847
1003
  pool: poolPda,
848
1004
  poolSecondary,
@@ -852,23 +1008,26 @@ export class NftStakingClient {
852
1008
  })
853
1009
  .instruction();
854
1010
  }
855
- async claimSecondaryRewards(projectId, poolId, secondaryRewards, fee) {
856
- const [poolPda] = getStakePoolPda(projectId, poolId);
1011
+ async claimSecondaryRewards(poolId, secondaryRewards, opts) {
1012
+ const pid = this.resolveProjectId(opts?.projectId);
1013
+ const [poolPda] = getStakePoolPda(pid, poolId);
857
1014
  const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
858
1015
  const staker = this.provider.wallet.publicKey;
859
1016
  const [stakerAccount] = getStakerAccountPda(poolId, staker);
860
1017
  const [stakerSecondary] = getStakerSecondaryRewardsPda(poolId, staker);
861
1018
  const [poolAuthority] = getPoolAuthorityPda(poolId);
862
- const feeAccts = this.resolveFeeAccounts(fee);
1019
+ const feeAccts = this.resolveFeeAccounts(opts?.fee);
1020
+ const [project] = getProjectPda(pid);
863
1021
  const remainingAccounts = [];
864
1022
  for (const sr of secondaryRewards) {
865
- const tokenProgram = await this.resolveTokenProgram(sr.mint);
866
- const vault = getAta(poolAuthority, sr.mint, tokenProgram);
867
- const stakerAta = getAta(staker, sr.mint, tokenProgram);
868
- remainingAccounts.push({ pubkey: vault, isSigner: false, isWritable: true }, { pubkey: stakerAta, isSigner: false, isWritable: true }, { pubkey: sr.mint, isSigner: false, isWritable: false }, { pubkey: tokenProgram, isSigner: false, isWritable: false });
1023
+ const _srMint = toPk(sr.mint);
1024
+ const tokenProgram = await this.resolveTokenProgram(_srMint);
1025
+ const vault = getAta(poolAuthority, _srMint, tokenProgram);
1026
+ const stakerAta = getAta(staker, _srMint, tokenProgram);
1027
+ remainingAccounts.push({ pubkey: vault, isSigner: false, isWritable: true }, { pubkey: stakerAta, isSigner: false, isWritable: true }, { pubkey: _srMint, isSigner: false, isWritable: false }, { pubkey: tokenProgram, isSigner: false, isWritable: false });
869
1028
  }
870
1029
  return this.program.methods
871
- .claimSecondaryRewards(new BN(projectId), new BN(poolId))
1030
+ .claimSecondaryRewards(new BN(pid), new BN(poolId))
872
1031
  .accountsStrict({
873
1032
  pool: poolPda,
874
1033
  poolSecondary,
@@ -876,10 +1035,12 @@ export class NftStakingClient {
876
1035
  stakerSecondary,
877
1036
  poolAuthority,
878
1037
  feeConfig: feeAccts.feeConfig,
1038
+ programRegistry: feeAccts.programRegistry,
879
1039
  treasury: feeAccts.treasury,
880
1040
  referralAccount: feeAccts.referralAccount,
881
1041
  solUsdPriceFeed: feeAccts.solUsdPriceFeed,
882
1042
  adminProgram: feeAccts.adminProgram,
1043
+ project,
883
1044
  staker,
884
1045
  tokenProgram: TOKEN_PROGRAM_ID,
885
1046
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
@@ -888,5 +1049,18 @@ export class NftStakingClient {
888
1049
  .remainingAccounts(remainingAccounts)
889
1050
  .instruction();
890
1051
  }
1052
+ async updatePoolSecondaryReward(poolId, rewardIndex, baseRate, lockTierRates, projectId) {
1053
+ const pid = this.resolveProjectId(projectId);
1054
+ const [poolPda] = getStakePoolPda(pid, poolId);
1055
+ const [poolSecondary] = getPoolSecondaryRewardsPda(poolId);
1056
+ return this.program.methods
1057
+ .updatePoolSecondaryReward(new BN(pid), new BN(poolId), rewardIndex, toBN(baseRate), lockTierRates.map(toBN))
1058
+ .accountsStrict({
1059
+ pool: poolPda,
1060
+ poolSecondary,
1061
+ authority: this.provider.wallet.publicKey,
1062
+ })
1063
+ .instruction();
1064
+ }
891
1065
  }
892
1066
  //# sourceMappingURL=client.js.map