@soltracer/nft-staking 0.2.9 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INTEGRATION.md CHANGED
@@ -280,70 +280,86 @@ Early-unstake penalties apply on exit when configured.
280
280
  #### Aggregating per-trait bonuses
281
281
 
282
282
  The on-chain instruction accepts a **single** `u64` `traitBonusRate` per claim — it has no notion of per-trait or
283
- per-NFT granularity. When a staker has N NFTs each with M bonus-bearing traits, the off-chain trait-authority server is
284
- responsible for:
285
-
286
- 1. Resolving the **active staked set** for the wallet (e.g. `client.fetchStakeEntriesByOwner(poolId, wallet)`).
287
- 2. Looking up the bonus metadata for every trait on every staked NFT (this comes from your own catalog — the
288
- chain stores no trait data).
289
- 3. **Summing** the per-trait bonuses into one number, using the pool's `traitBonusMode`:
290
- - `FixedExtra`: sum absolute reward-per-interval values across all bonus traits.
291
- - `BaseMultiplier`: sum BPS values across all bonus traits (the result scales the whole staker rate).
292
- 4. Signing the proof for that aggregated rate with the pool's `traitAuthority` keypair.
293
-
294
- Use `aggregateTraitBonusRate` to do step 3 safely (it enforces mode/field consistency and rejects mixing `bonusBps`
295
- with `fixedExtra` on the same trait):
283
+ per-NFT granularity, and it cannot read NFT metadata. Aggregation lives entirely off-chain in the trait-authority
284
+ server. The intended flow:
285
+
286
+ 1. **Client request.** The wallet calls your API with `{ wallet, poolId, mints }` (the mints it wants to claim against).
287
+ 2. **Ownership / stake validation.** The API resolves the wallet's active stake entries
288
+ (`client.fetchStakeEntriesByOwner(poolId, wallet)`) and **drops** any mint not present — never trust the client's
289
+ list. Anything that survives is provably staked by `wallet` in `pool`.
290
+ 3. **Trait resolution.** For each surviving mint, fetch its trait list from your own source of truth (collection JSON,
291
+ Metaplex on-chain metadata, indexer, internal DB). The chain stores no trait data.
292
+ 4. **Catalog lookup.** Each `(traitType, value)` pair is checked against your project's bonus catalog. Traits without
293
+ an entry contribute nothing.
294
+ 5. **Mode-aware sum.** Bonuses are summed according to the pool's `rewardConfig.traitBonusMode`:
295
+ - `FixedExtra`: catalog uses `fixedExtra` (raw reward per `rateInterval`); each matched trait adds its value.
296
+ - `BaseMultiplier`: catalog uses `bonusBps` (10_000 = +100%); each matched trait adds its BPS to a single boost that
297
+ scales the staker's current `effective_rate` for the accrual window.
298
+ 6. **Sign and return.** Sign the resulting `u64` with the pool's `traitAuthority` keypair; return signature + rate to
299
+ the client.
300
+
301
+ The SDK ships `computeTraitBonusRate` for steps 4–5. It takes the validated NFT/trait list and a bonus catalog, enforces
302
+ mode/field consistency, and returns both the aggregated rate and a per-NFT breakdown (handy for receipts or UI tooltips):
296
303
 
297
304
  ```ts
298
305
  import {
299
- aggregateTraitBonusRate,
300
306
  buildTraitProofMessage,
307
+ computeTraitBonusRate,
308
+ type NftTraitInput,
309
+ type TraitBonusCatalogEntry,
301
310
  } from "@soltracer/nft-staking"
311
+ import nacl from "tweetnacl"
302
312
 
303
- // 1. Resolve staker's active NFTs
304
- const entries = await client.fetchStakeEntriesByOwner(poolId, wallet)
305
-
306
- // 2. Look up bonuses for each trait of each staked NFT (from your catalog)
307
- // BaseMultiplier example pool grants BPS bonuses per trait.
308
- const traitBonuses: Array<{ bonusBps?: number; fixedExtra?: number }> = []
309
- for (const entry of entries) {
310
- const meta = await catalog.getNftTraits(entry.nftMint)
311
- // meta looks like: [{ traitType: "Background", value: "Mythic", bonusBps: 2500 }, …]
312
- for (const trait of meta) {
313
- if (trait.bonusBps && trait.bonusBps > 0) {
314
- traitBonuses.push({ bonusBps: trait.bonusBps })
315
- }
316
- }
313
+ // ── Server: POST /claim/trait-proof body: { wallet, poolId, mints }
314
+ async function buildProof(req: { wallet: PublicKey; poolId: number; mints: string[] }) {
315
+ // 2. Validate ownership / current stake state.
316
+ const entries = await client.fetchStakeEntriesByOwner(req.poolId, req.wallet)
317
+ const stakedSet = new Set(entries.map((e) => e.nftMint.toBase58()))
318
+ const ownedMints = req.mints.filter((m) => stakedSet.has(m))
319
+
320
+ // 3. Resolve traits from your collection catalog.
321
+ const nfts: NftTraitInput[] = await Promise.all(
322
+ ownedMints.map(async (mint) => ({
323
+ mint,
324
+ traits: await catalog.getTraits(mint), // [{ traitType, value }, ..]
325
+ })),
326
+ )
327
+
328
+ // 4 + 5. Mode-aware aggregation against the project's bonus catalog.
329
+ const pool = await client.fetchStakePool(undefined, req.poolId)
330
+ const bonusCatalog: TraitBonusCatalogEntry[] = [
331
+ { traitType: "Background", value: "Mythic", bonusBps: 2500 }, // +25%
332
+ { traitType: "Eyes", value: "Laser", bonusBps: 1000 }, // +10%
333
+ { traitType: "Head", value: "Gold Crown", bonusBps: 500 }, // +5%
334
+ ]
335
+ const { traitBonusRate, perNft } = computeTraitBonusRate({
336
+ traitBonusMode: pool.rewardConfig.traitBonusMode as 0 | 1 | 2,
337
+ catalog: bonusCatalog,
338
+ nfts,
339
+ })
340
+
341
+ // 6. Sign the aggregated rate.
342
+ const stakerAccount = await client.fetchStakerAccount(req.poolId, req.wallet)
343
+ const message = buildTraitProofMessage({
344
+ pool: pool.address,
345
+ wallet: req.wallet,
346
+ traitBonusRate,
347
+ totalClaimed: stakerAccount.totalClaimed,
348
+ })
349
+ const signature = nacl.sign.detached(message, traitAuthority.secretKey)
350
+ return { traitBonusRate: traitBonusRate.toString(), signature, perNft }
317
351
  }
318
-
319
- // 3. Aggregate to a single u64 (mode 2 = BaseMultiplier).
320
- // Result: 4_000 means +40% over the staker's current effective_rate for this claim window.
321
- const pool = await client.fetchStakePool(undefined, poolId)
322
- const traitBonusRate = aggregateTraitBonusRate(
323
- traitBonuses,
324
- pool.rewardConfig.traitBonusMode as 0 | 1 | 2,
325
- )
326
-
327
- // 4. Sign the aggregated rate.
328
- const stakerAccount = await client.fetchStakerAccount(poolId, wallet)
329
- const message = buildTraitProofMessage({
330
- pool: poolPda,
331
- wallet,
332
- traitBonusRate,
333
- totalClaimed: stakerAccount.totalClaimed,
334
- })
335
- const signature = nacl.sign.detached(message, traitAuthority.secretKey)
336
352
  ```
337
353
 
338
- > ⚠️ Re-aggregate on every claim. The active staked set, traits, and per-trait bonus tables can all change between
339
- > claims, and the on-chain message also binds `staker.totalClaimed` which advances after every successful claim.
354
+ > ⚠️ Re-run the entire pipeline on every claim. The staked set, NFT traits, and the staker's `totalClaimed` nonce can
355
+ > all change between claims; a stale proof is rejected on-chain.
340
356
 
341
357
  Examples per mode:
342
358
 
343
- | Mode | Per-trait field | What 1 trait contributes | Final `traitBonusRate` |
359
+ | Mode | Catalog field | What 1 matched trait contributes | Final `traitBonusRate` |
344
360
  | --- | --- | --- | --- |
345
- | `FixedExtra` | `fixedExtra: 100` | +100 reward tokens per `rateInterval` | Sum of every staked NFT's per-trait `fixedExtra`. |
346
- | `BaseMultiplier` | `bonusBps: 500` | +5% over the staker's current effective rate | Sum of every staked NFT's per-trait BPS. `10_000` ⇒ 2x base. |
361
+ | `FixedExtra` | `fixedExtra: 100` | +100 reward tokens per `rateInterval` | Sum across every matched trait on every validated NFT. |
362
+ | `BaseMultiplier` | `bonusBps: 500` | +5% over the staker's current effective rate | Sum across every matched trait on every validated NFT. `10_000` ⇒ 2x base for that claim window. |
347
363
 
348
364
  Trait proof messages bind the pool, wallet, signed rate, and the staker account's strictly-monotonic `totalClaimed`
349
365
  counter. A new proof is required after every successful claim because `totalClaimed` advances.
package/dist/index.d.ts CHANGED
@@ -4,6 +4,6 @@ export { type NftStaking as NftStakingIDLType } from "./idl";
4
4
  export { default as NftStakingIDL } from "./idl.json";
5
5
  export * from "./errors";
6
6
  export * from "./helpers";
7
- export { buildTraitProofMessage, TRAIT_PROOF_MSG_LEN, aggregateTraitBonusRate } from "./traitProof";
7
+ export { buildTraitProofMessage, TRAIT_PROOF_MSG_LEN, aggregateTraitBonusRate, computeTraitBonusRate, type TraitBonusCatalogEntry, type NftTraitInput, type ComputeTraitBonusResult, } from "./traitProof";
8
8
  export { GATE_TYPE_NONE, GATE_TYPE_WALLET, GATE_TYPE_TOKEN_MINT, type GateType, type MerkleTree, hashLeaf, hashPair, buildMerkleTree, getMerkleProof, proofToAnchorArg, rootToAnchorArg, } from "./merkle";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,KAAK,UAAU,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,YAAY,CAAA;AACrD,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACnG,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,KAAK,UAAU,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,YAAY,CAAA;AACrD,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,KAAK,uBAAuB,GAC7B,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,UAAU,CAAA"}
package/dist/index.js CHANGED
@@ -3,6 +3,6 @@ export { NFT_STAKING_PROGRAM_ID, getStakeConfigPda, getStakePoolPda, getStakeEnt
3
3
  export { default as NftStakingIDL } from "./idl.json";
4
4
  export * from "./errors";
5
5
  export * from "./helpers";
6
- export { buildTraitProofMessage, TRAIT_PROOF_MSG_LEN, aggregateTraitBonusRate } from "./traitProof";
6
+ export { buildTraitProofMessage, TRAIT_PROOF_MSG_LEN, aggregateTraitBonusRate, computeTraitBonusRate, } from "./traitProof";
7
7
  export { GATE_TYPE_NONE, GATE_TYPE_WALLET, GATE_TYPE_TOKEN_MINT, hashLeaf, hashPair, buildMerkleTree, getMerkleProof, proofToAnchorArg, rootToAnchorArg, } from "./merkle";
8
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAKjB,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,YAAY,CAAA;AACrD,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACnG,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EAGpB,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAKjB,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,YAAY,CAAA;AACrD,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,GAItB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EAGpB,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,UAAU,CAAA"}
@@ -63,35 +63,94 @@ export declare function buildTraitProofMessage(params: {
63
63
  * The on-chain `claim_rewards` instruction accepts a **single** `u64`
64
64
  * `traitBonusRate` per claim — the chain knows nothing about per-trait
65
65
  * granularity. Aggregation across N staked NFTs (each with M traits) is the
66
- * caller's responsibility, and the math depends on the pool's
67
- * `rewardConfig.traitBonusMode`:
66
+ * trait-authority server's responsibility.
68
67
  *
69
- * - `0` / `None` — proofs disabled. Any non-zero rate is rejected.
70
- * - `1` / `FixedExtra` — `traitBonusRate` is **absolute extra reward per
71
- * `rateInterval`** added to the staker's effective rate for the claim
72
- * accrual window. Sum per-trait fixed bonuses across every active staked
73
- * NFT (and every bonus-bearing trait on each).
74
- * - `2` / `BaseMultiplier` — `traitBonusRate` is **bonus BPS** applied to the
75
- * staker's CURRENT `effective_rate` (already includes lock-tier rates).
76
- * `10_000` = +100% (2x base for the window). Sum per-trait BPS bonuses the
77
- * same way — the bonus is a scalar over the whole staker rate.
68
+ * Intended backend flow:
78
69
  *
79
- * `bonusBps` and `fixedExtra` fields are mutually exclusive; mixing both in
80
- * one trait entry throws. Traits without bonuses can be omitted.
70
+ * 1. Client sends `{ wallet, poolId, mints: [..] }` to your API.
71
+ * 2. API validates `mints` are currently staked by `wallet` in `pool`
72
+ * (e.g. via `fetchStakeEntriesByOwner`) and DROPS any it cannot prove.
73
+ * 3. API resolves each surviving NFT's trait list from its own metadata
74
+ * source (off-chain JSON, on-chain metaplex data, indexer, etc.).
75
+ * 4. API looks up each `(traitType, value)` pair in the project's bonus
76
+ * catalog. Unmatched traits contribute nothing.
77
+ * 5. API sums the matched bonuses according to the pool's
78
+ * `rewardConfig.traitBonusMode` and signs the resulting `u64`.
79
+ *
80
+ * Modes:
81
+ *
82
+ * - `0` / `None` — proofs disabled. Always returns `0n`.
83
+ * - `1` / `FixedExtra` — bonuses are **absolute reward per `rateInterval`**.
84
+ * Summed and added on top of the staker's effective rate for the accrual
85
+ * window. Catalog entries MUST use `fixedExtra`.
86
+ * - `2` / `BaseMultiplier` — bonuses are **BPS over the staker's current
87
+ * `effective_rate`** (which already includes lock-tier rates). `10_000`
88
+ * means +100% (2x base). Summed BPS apply once to the staker rate.
89
+ * Catalog entries MUST use `bonusBps`.
90
+ *
91
+ * Catalog entries with both `bonusBps` and `fixedExtra` set, or with the wrong
92
+ * field for the active mode, are rejected. Mints can repeat the same trait
93
+ * type/value — each NFT contributes independently.
94
+ *
95
+ * @returns `{ traitBonusRate, perNft }` where `perNft` is the per-mint
96
+ * breakdown (useful for receipts, debugging, or surfacing a tooltip in the UI).
81
97
  *
82
98
  * @example
83
99
  * ```ts
84
- * // Pool is in BaseMultiplier mode. Each staked NFT exposes its trait list.
85
- * const traits = [
86
- * // NFT 1 "Gold" head (+5%), "Laser Eyes" (+10%)
87
- * { bonusBps: 500 }, { bonusBps: 1000 },
88
- * // NFT 2 "Mythic Background" (+25%)
89
- * { bonusBps: 2500 },
90
- * ]
91
- * const rate = aggregateTraitBonusRate(traits, 2) // → 4000 (i.e. +40% for the window)
92
- * const message = buildTraitProofMessage({ pool, wallet, traitBonusRate: rate, totalClaimed })
100
+ * // Backend after ownership validation:
101
+ * const result = computeTraitBonusRate({
102
+ * traitBonusMode: pool.rewardConfig.traitBonusMode as 0 | 1 | 2,
103
+ * catalog: [
104
+ * { traitType: "Background", value: "Mythic", bonusBps: 2500 },
105
+ * { traitType: "Eyes", value: "Laser", bonusBps: 1000 },
106
+ * { traitType: "Head", value: "Gold Crown", bonusBps: 500 },
107
+ * ],
108
+ * nfts: validatedStakedNfts, // [{ mint, traits: [{ traitType, value }] }, ..]
109
+ * })
110
+ *
111
+ * const message = buildTraitProofMessage({
112
+ * pool, wallet,
113
+ * traitBonusRate: result.traitBonusRate,
114
+ * totalClaimed: stakerAccount.totalClaimed,
115
+ * })
93
116
  * ```
94
117
  */
118
+ export type TraitBonusCatalogEntry = {
119
+ traitType: string;
120
+ value: string;
121
+ /** Bonus BPS — required when `traitBonusMode === 2` (BaseMultiplier). */
122
+ bonusBps?: number | bigint;
123
+ /** Extra reward per `rateInterval` — required when `traitBonusMode === 1` (FixedExtra). */
124
+ fixedExtra?: number | bigint;
125
+ };
126
+ export type NftTraitInput = {
127
+ mint: PkInput | string;
128
+ /** Ordered or unordered list of an NFT's traits, after ownership validation. */
129
+ traits: ReadonlyArray<{
130
+ traitType: string;
131
+ value: string;
132
+ }>;
133
+ };
134
+ export type ComputeTraitBonusResult = {
135
+ /** Aggregated u64 rate to sign and include in the claim. */
136
+ traitBonusRate: bigint;
137
+ /** Per-NFT breakdown (mint → total bonus contributed + matched-trait count). */
138
+ perNft: Array<{
139
+ mint: string;
140
+ bonus: bigint;
141
+ matchedTraits: number;
142
+ }>;
143
+ };
144
+ export declare function computeTraitBonusRate(params: {
145
+ traitBonusMode: 0 | 1 | 2;
146
+ catalog: ReadonlyArray<TraitBonusCatalogEntry>;
147
+ nfts: ReadonlyArray<NftTraitInput>;
148
+ }): ComputeTraitBonusResult;
149
+ /**
150
+ * @deprecated Use `computeTraitBonusRate` instead — it accepts the real per-NFT
151
+ * trait input and a bonus catalog, mirroring the backend flow. Retained for
152
+ * call sites that already pre-resolved a flat bonus array.
153
+ */
95
154
  export declare function aggregateTraitBonusRate(traits: ReadonlyArray<{
96
155
  bonusBps?: number | bigint;
97
156
  fixedExtra?: number | bigint;
@@ -1 +1 @@
1
- {"version":3,"file":"traitProof.d.ts","sourceRoot":"","sources":["../src/traitProof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAQ,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAElE,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAcrC;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,cAAc,EAAE,OAAO,CAAA;IACvB,8DAA8D;IAC9D,YAAY,EAAE,OAAO,CAAA;CACtB,GAAG,MAAM,CAOT;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC,EACnF,cAAc,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GACxB,MAAM,CAqCR"}
1
+ {"version":3,"file":"traitProof.d.ts","sourceRoot":"","sources":["../src/traitProof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAQ,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAElE,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAcrC;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,cAAc,EAAE,OAAO,CAAA;IACvB,8DAA8D;IAC9D,YAAY,EAAE,OAAO,CAAA;CACtB,GAAG,MAAM,CAOT;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IACtB,gFAAgF;IAChF,MAAM,EAAE,aAAa,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC5D,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAA;IACtB,gFAAgF;IAChF,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACtE,CAAA;AAiCD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,cAAc,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACzB,OAAO,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;IAC9C,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;CACnC,GAAG,uBAAuB,CAuC1B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC,EACnF,cAAc,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GACxB,MAAM,CAmCR"}
@@ -44,64 +44,67 @@ export function buildTraitProofMessage(params) {
44
44
  u64LE(params.totalClaimed).copy(msg, 72);
45
45
  return msg;
46
46
  }
47
+ function normalizeKey(s) {
48
+ return s.trim().toLowerCase();
49
+ }
50
+ function bonusFromCatalogEntry(entry, traitBonusMode) {
51
+ const bps = BigInt(entry.bonusBps ?? 0);
52
+ const extra = BigInt(entry.fixedExtra ?? 0);
53
+ if (bps !== 0n && extra !== 0n) {
54
+ throw new Error(`computeTraitBonusRate: catalog entry "${entry.traitType}=${entry.value}" sets both bonusBps and fixedExtra; pick one.`);
55
+ }
56
+ if (traitBonusMode === 1) {
57
+ if (bps !== 0n) {
58
+ throw new Error(`computeTraitBonusRate: traitBonusMode = FixedExtra but catalog entry "${entry.traitType}=${entry.value}" uses bonusBps. Use fixedExtra (raw reward per interval).`);
59
+ }
60
+ return extra;
61
+ }
62
+ if (extra !== 0n) {
63
+ throw new Error(`computeTraitBonusRate: traitBonusMode = BaseMultiplier but catalog entry "${entry.traitType}=${entry.value}" uses fixedExtra. Use bonusBps (10_000 = +100%).`);
64
+ }
65
+ return bps;
66
+ }
67
+ export function computeTraitBonusRate(params) {
68
+ if (params.traitBonusMode === 0) {
69
+ return { traitBonusRate: 0n, perNft: [] };
70
+ }
71
+ const mode = params.traitBonusMode;
72
+ // Build a lookup keyed by normalized "type::value".
73
+ // Validates every catalog entry up-front so misconfigured entries are
74
+ // surfaced even if no NFT references them.
75
+ const lookup = new Map();
76
+ for (const entry of params.catalog) {
77
+ const key = `${normalizeKey(entry.traitType)}::${normalizeKey(entry.value)}`;
78
+ if (lookup.has(key)) {
79
+ throw new Error(`computeTraitBonusRate: duplicate catalog entry for "${entry.traitType}=${entry.value}".`);
80
+ }
81
+ lookup.set(key, bonusFromCatalogEntry(entry, mode));
82
+ }
83
+ let total = 0n;
84
+ const perNft = [];
85
+ for (const nft of params.nfts) {
86
+ let nftBonus = 0n;
87
+ let matched = 0;
88
+ for (const trait of nft.traits) {
89
+ const hit = lookup.get(`${normalizeKey(trait.traitType)}::${normalizeKey(trait.value)}`);
90
+ if (hit === undefined || hit === 0n)
91
+ continue;
92
+ nftBonus += hit;
93
+ matched += 1;
94
+ }
95
+ total += nftBonus;
96
+ perNft.push({
97
+ mint: typeof nft.mint === "string" ? nft.mint : toPk(nft.mint).toBase58(),
98
+ bonus: nftBonus,
99
+ matchedTraits: matched,
100
+ });
101
+ }
102
+ return { traitBonusRate: total, perNft };
103
+ }
47
104
  /**
48
- * Example (off-chain trait-authority server):
49
- *
50
- * ```ts
51
- * import nacl from "tweetnacl"
52
- * import { Ed25519Program } from "@solana/web3.js"
53
- * import { buildTraitProofMessage } from "@soltracer/nft-staking"
54
- *
55
- * const message = buildTraitProofMessage({
56
- * pool,
57
- * wallet: staker,
58
- * traitBonusRate,
59
- * totalClaimed: stakerAccount.totalClaimed,
60
- * })
61
- * const signature = nacl.sign.detached(message, traitAuthority.secretKey)
62
- * const ed25519Ix = Ed25519Program.createInstructionWithPublicKey({
63
- * publicKey: traitAuthority.publicKey.toBytes(),
64
- * message,
65
- * signature,
66
- * })
67
- * const claimIx = await client.claimRewards(poolId, { traitBonusRate })
68
- * await provider.sendAndConfirm(new Transaction().add(ed25519Ix, claimIx))
69
- * ```
70
- */
71
- /**
72
- * Mode-aware trait-bonus rate aggregator.
73
- *
74
- * The on-chain `claim_rewards` instruction accepts a **single** `u64`
75
- * `traitBonusRate` per claim — the chain knows nothing about per-trait
76
- * granularity. Aggregation across N staked NFTs (each with M traits) is the
77
- * caller's responsibility, and the math depends on the pool's
78
- * `rewardConfig.traitBonusMode`:
79
- *
80
- * - `0` / `None` — proofs disabled. Any non-zero rate is rejected.
81
- * - `1` / `FixedExtra` — `traitBonusRate` is **absolute extra reward per
82
- * `rateInterval`** added to the staker's effective rate for the claim
83
- * accrual window. Sum per-trait fixed bonuses across every active staked
84
- * NFT (and every bonus-bearing trait on each).
85
- * - `2` / `BaseMultiplier` — `traitBonusRate` is **bonus BPS** applied to the
86
- * staker's CURRENT `effective_rate` (already includes lock-tier rates).
87
- * `10_000` = +100% (2x base for the window). Sum per-trait BPS bonuses the
88
- * same way — the bonus is a scalar over the whole staker rate.
89
- *
90
- * `bonusBps` and `fixedExtra` fields are mutually exclusive; mixing both in
91
- * one trait entry throws. Traits without bonuses can be omitted.
92
- *
93
- * @example
94
- * ```ts
95
- * // Pool is in BaseMultiplier mode. Each staked NFT exposes its trait list.
96
- * const traits = [
97
- * // NFT 1 — "Gold" head (+5%), "Laser Eyes" (+10%)
98
- * { bonusBps: 500 }, { bonusBps: 1000 },
99
- * // NFT 2 — "Mythic Background" (+25%)
100
- * { bonusBps: 2500 },
101
- * ]
102
- * const rate = aggregateTraitBonusRate(traits, 2) // → 4000 (i.e. +40% for the window)
103
- * const message = buildTraitProofMessage({ pool, wallet, traitBonusRate: rate, totalClaimed })
104
- * ```
105
+ * @deprecated Use `computeTraitBonusRate` instead — it accepts the real per-NFT
106
+ * trait input and a bonus catalog, mirroring the backend flow. Retained for
107
+ * call sites that already pre-resolved a flat bonus array.
105
108
  */
106
109
  export function aggregateTraitBonusRate(traits, traitBonusMode) {
107
110
  if (traitBonusMode === 0) {
@@ -118,14 +121,12 @@ export function aggregateTraitBonusRate(traits, traitBonusMode) {
118
121
  throw new Error("aggregateTraitBonusRate: a single trait must set bonusBps OR fixedExtra, not both.");
119
122
  }
120
123
  if (traitBonusMode === 1) {
121
- // FixedExtra — sum absolute per-interval bonuses.
122
124
  if (bps !== 0n) {
123
125
  throw new Error("aggregateTraitBonusRate: traitBonusMode = FixedExtra expects fixedExtra (per-interval reward), not bonusBps.");
124
126
  }
125
127
  sum += extra;
126
128
  }
127
129
  else {
128
- // BaseMultiplier — sum BPS bonuses.
129
130
  if (extra !== 0n) {
130
131
  throw new Error("aggregateTraitBonusRate: traitBonusMode = BaseMultiplier expects bonusBps (10_000 = +100%), not fixedExtra.");
131
132
  }
@@ -1 +1 @@
1
- {"version":3,"file":"traitProof.js","sourceRoot":"","sources":["../src/traitProof.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"traitProof.js","sourceRoot":"","sources":["../src/traitProof.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soltracer/nft-staking",
3
- "version": "0.2.9",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",