@soltracer/nft-staking 0.3.1 → 0.4.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 +203 -112
- package/dist/client.d.ts +15 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +28 -4
- package/dist/client.js.map +1 -1
- package/dist/idl.d.ts +23 -14
- package/dist/idl.d.ts.map +1 -1
- package/dist/idl.json +42 -33
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/traitProof.d.ts +170 -244
- package/dist/traitProof.d.ts.map +1 -1
- package/dist/traitProof.js +108 -174
- package/dist/traitProof.js.map +1 -1
- package/package.json +2 -2
package/dist/traitProof.d.ts
CHANGED
|
@@ -1,21 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Trait-bonus proof builder for NFT-staking `claim_rewards`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Design summary
|
|
5
|
+
* --------------
|
|
6
|
+
* The on-chain `claim_rewards` instruction accepts a SINGLE u64
|
|
7
|
+
* `traitBonusRate` per claim. When `pool.reward_config.trait_bonus_enabled`
|
|
8
|
+
* is `true`, that rate is added directly to the staker's effective rate for
|
|
9
|
+
* the accrual window. The chain has zero per-NFT or per-trait awareness —
|
|
10
|
+
* ALL bonus math (trait lookups, per-NFT multipliers, caps, etc.) happens
|
|
11
|
+
* off-chain in the project's trait-authority server, which signs the final
|
|
12
|
+
* aggregated rate.
|
|
13
|
+
*
|
|
14
|
+
* Why per-NFT (not per-staker) multipliers
|
|
15
|
+
* ----------------------------------------
|
|
16
|
+
* An older design exposed a `BaseMultiplier` mode on-chain that multiplied
|
|
17
|
+
* the staker's ENTIRE effective rate (all NFTs combined). That meant a
|
|
18
|
+
* single "Mythic 2x" NFT doubled rewards for every plain NFT in the same
|
|
19
|
+
* claim — cross-contamination across NFTs. The new model evaluates each
|
|
20
|
+
* NFT's bonuses independently, applies its own optional multiplier to its
|
|
21
|
+
* own bonus sum, then sums those isolated per-NFT bonuses into the single
|
|
22
|
+
* signed `u64`. One NFT's multiplier never touches another NFT's reward.
|
|
23
|
+
*
|
|
24
|
+
* Ed25519 message layout — 80 bytes (LE where applicable):
|
|
9
25
|
*
|
|
10
26
|
* [0..32] pool (PublicKey bytes)
|
|
11
27
|
* [32..64] staker wallet (PublicKey bytes)
|
|
12
|
-
* [64..72]
|
|
13
|
-
* [72..80]
|
|
28
|
+
* [64..72] traitBonusRate u64 (LE)
|
|
29
|
+
* [72..80] totalClaimed u64 (LE — strictly monotonic replay nonce)
|
|
14
30
|
*
|
|
15
|
-
* Sign
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* invokes `claimRewards(..., traitBonusRate)`.
|
|
31
|
+
* Sign with the pool's trait-authority Ed25519 keypair (or the global
|
|
32
|
+
* `stakeConfig.authority` when the pool has no override) and prepend the
|
|
33
|
+
* Ed25519 precompile instruction in the same transaction as `claimRewards`.
|
|
19
34
|
*/
|
|
20
35
|
import { type PkInput, type BnInput } from "@soltracer/core";
|
|
21
36
|
/** Fixed message length consumed by the on-chain Ed25519 verifier. */
|
|
@@ -23,8 +38,8 @@ export declare const TRAIT_PROOF_MSG_LEN = 80;
|
|
|
23
38
|
/**
|
|
24
39
|
* Build the 80-byte trait-proof message exactly as the on-chain handler
|
|
25
40
|
* reconstructs it. `totalClaimed` must be the LIVE value of
|
|
26
|
-
* `StakerAccount.totalClaimed` (
|
|
27
|
-
*
|
|
41
|
+
* `StakerAccount.totalClaimed` (fetched within the same tx prep window —
|
|
42
|
+
* otherwise the signature is rejected once the nonce advances).
|
|
28
43
|
*/
|
|
29
44
|
export declare function buildTraitProofMessage(params: {
|
|
30
45
|
pool: PkInput;
|
|
@@ -34,262 +49,173 @@ export declare function buildTraitProofMessage(params: {
|
|
|
34
49
|
totalClaimed: BnInput;
|
|
35
50
|
}): Buffer;
|
|
36
51
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* pool,
|
|
46
|
-
* wallet: staker,
|
|
47
|
-
* traitBonusRate,
|
|
48
|
-
* totalClaimed: stakerAccount.totalClaimed,
|
|
49
|
-
* })
|
|
50
|
-
* const signature = nacl.sign.detached(message, traitAuthority.secretKey)
|
|
51
|
-
* const ed25519Ix = Ed25519Program.createInstructionWithPublicKey({
|
|
52
|
-
* publicKey: traitAuthority.publicKey.toBytes(),
|
|
53
|
-
* message,
|
|
54
|
-
* signature,
|
|
55
|
-
* })
|
|
56
|
-
* const claimIx = await client.claimRewards(poolId, { traitBonusRate })
|
|
57
|
-
* await provider.sendAndConfirm(new Transaction().add(ed25519Ix, claimIx))
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
/**
|
|
61
|
-
* Mode-aware trait-bonus rate aggregator.
|
|
62
|
-
*
|
|
63
|
-
* The on-chain `claim_rewards` instruction accepts a **single** `u64`
|
|
64
|
-
* `traitBonusRate` per claim — the chain knows nothing about per-trait
|
|
65
|
-
* granularity. Aggregation across N staked NFTs (each with M traits) is the
|
|
66
|
-
* trait-authority server's responsibility.
|
|
67
|
-
*
|
|
68
|
-
* Intended backend flow:
|
|
69
|
-
*
|
|
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).
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```ts
|
|
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
|
-
* })
|
|
116
|
-
* ```
|
|
52
|
+
* One catalog row. Each `(traitType, value)` pair maps to ONE absolute bonus
|
|
53
|
+
* amount measured in the same units as `rewardConfig.baseRate` (raw token
|
|
54
|
+
* units per `rateInterval`). To express the catalog in human units, multiply
|
|
55
|
+
* by `10 ** rewardDecimals` before passing it in.
|
|
56
|
+
*
|
|
57
|
+
* Example: catalog row `{ traitType: "Rarity", value: "Mythic", bonus: 25n }`
|
|
58
|
+
* with a `rateInterval` of 86_400s means "this trait adds 25 raw reward
|
|
59
|
+
* units per day to the NFT that carries it".
|
|
117
60
|
*/
|
|
118
|
-
export
|
|
61
|
+
export interface TraitBonusCatalogEntry {
|
|
119
62
|
traitType: string;
|
|
120
63
|
value: string;
|
|
121
|
-
/**
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
64
|
+
/** Raw reward units per `rateInterval` to add for this trait. */
|
|
65
|
+
bonus: bigint;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Storage-agnostic store interface — implement with Prisma, Drizzle, Firestore,
|
|
69
|
+
* in-memory, etc.
|
|
70
|
+
*
|
|
71
|
+
* Catalog rows are keyed by **NFT collection mint**, NOT by pool id. A single
|
|
72
|
+
* collection can be wired into many pools (e.g. a 30-day pool and a 90-day
|
|
73
|
+
* pool over the same collection) and they all share one set of trait bonuses.
|
|
74
|
+
* The pool only contributes the trait-bonus *enable flag* and the signing
|
|
75
|
+
* authority; the bonus values themselves are a property of the collection.
|
|
76
|
+
*/
|
|
77
|
+
export interface TraitBonusStore {
|
|
78
|
+
/**
|
|
79
|
+
* Return every catalog entry that applies to an NFT collection.
|
|
80
|
+
*
|
|
81
|
+
* `collectionMint` is `pool.collectionMint` (base58). For pools with no
|
|
82
|
+
* configured collection (open-set pools), pass the empty string or call
|
|
83
|
+
* with `Pubkey::default().toBase58()` — the store can return `[]`.
|
|
84
|
+
*/
|
|
85
|
+
listForCollection(collectionMint: string): Promise<TraitBonusCatalogEntry[]>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* In-memory catalog suitable for tests and small static configurations.
|
|
89
|
+
* Keys are collection mints (base58).
|
|
90
|
+
*/
|
|
91
|
+
export declare class InMemoryTraitBonusStore implements TraitBonusStore {
|
|
92
|
+
private readonly entriesByCollection;
|
|
93
|
+
constructor(entriesByCollection: Map<string, TraitBonusCatalogEntry[]>);
|
|
94
|
+
static from(entries: Record<string, TraitBonusCatalogEntry[]>): InMemoryTraitBonusStore;
|
|
95
|
+
listForCollection(collectionMint: string): Promise<TraitBonusCatalogEntry[]>;
|
|
96
|
+
}
|
|
97
|
+
/** Traits attached to a single staked NFT. */
|
|
98
|
+
export interface NftTraitInput {
|
|
99
|
+
/** Mint of the staked NFT (string only used for diagnostics). */
|
|
100
|
+
mint: string;
|
|
101
|
+
/** Trait pairs in `[traitType, value]` form. */
|
|
102
|
+
traits: Array<{
|
|
130
103
|
traitType: string;
|
|
131
104
|
value: string;
|
|
132
105
|
}>;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Optional per-NFT multiplier in BPS applied ONLY to this NFT's own bonus
|
|
108
|
+
* total. 10_000 = 1× (no change). 20_000 = 2× this NFT's bonus. Multipliers
|
|
109
|
+
* NEVER cross NFTs — they cannot inflate another NFT's reward.
|
|
110
|
+
*
|
|
111
|
+
* Leave undefined (or 10_000) for plain NFTs. Project teams that want to
|
|
112
|
+
* reward rare NFTs disproportionately apply it here.
|
|
113
|
+
*/
|
|
114
|
+
multiplierBps?: number;
|
|
115
|
+
}
|
|
116
|
+
export interface PerNftBonus {
|
|
117
|
+
mint: string;
|
|
118
|
+
/** Sum of catalog bonuses matched on this NFT, after any per-NFT multiplier. */
|
|
119
|
+
bonus: bigint;
|
|
120
|
+
}
|
|
121
|
+
export interface TraitBonusComputation {
|
|
122
|
+
/** Final aggregated `u64` to feed into the signed message and `claimRewards`. */
|
|
136
123
|
traitBonusRate: bigint;
|
|
137
|
-
/** Per-NFT breakdown
|
|
138
|
-
perNft:
|
|
139
|
-
|
|
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;
|
|
124
|
+
/** Per-NFT breakdown — useful for surfacing "you earned X from this NFT" in UI. */
|
|
125
|
+
perNft: PerNftBonus[];
|
|
126
|
+
}
|
|
149
127
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
128
|
+
* Aggregate trait bonuses into a single absolute `u64` rate.
|
|
129
|
+
*
|
|
130
|
+
* Algorithm (per NFT, independently):
|
|
131
|
+
* 1. For every `(traitType, value)` on the NFT, look it up in `catalog`.
|
|
132
|
+
* 2. Sum every matched `bonus`. Unmatched traits contribute 0.
|
|
133
|
+
* 3. If `multiplierBps` is set, multiply the NFT's bonus sum by it / 10_000.
|
|
134
|
+
* (Floor division — bonuses are integer raw units.)
|
|
135
|
+
*
|
|
136
|
+
* Final result = sum of per-NFT bonuses. A multiplier on one NFT cannot
|
|
137
|
+
* touch another NFT's contribution, eliminating the cross-contamination bug
|
|
138
|
+
* present in the old on-chain `BaseMultiplier` mode.
|
|
153
139
|
*/
|
|
154
|
-
export declare function
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
140
|
+
export declare function computeTraitBonusRate(params: {
|
|
141
|
+
catalog: TraitBonusCatalogEntry[];
|
|
142
|
+
nfts: NftTraitInput[];
|
|
143
|
+
}): TraitBonusComputation;
|
|
158
144
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* The SDK does not care where you persist this data — Prisma, Drizzle, raw
|
|
162
|
-
* Postgres, Mongo, KV, in-memory, REST — implement this interface against
|
|
163
|
-
* whatever backs your admin UI. Each `(traitType, value)` row carries the
|
|
164
|
-
* bonus for that pair.
|
|
145
|
+
* Resolve the trait list for a staked mint. Implementations typically read
|
|
146
|
+
* from off-chain metadata, an indexer, or a cached project DB.
|
|
165
147
|
*/
|
|
166
|
-
export
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
poolId: number;
|
|
174
|
-
projectId?: string | number;
|
|
175
|
-
}): Promise<TraitBonusCatalogEntry[]>;
|
|
176
|
-
}
|
|
148
|
+
export type NftTraitResolver = (mint: string) => Promise<{
|
|
149
|
+
traits: Array<{
|
|
150
|
+
traitType: string;
|
|
151
|
+
value: string;
|
|
152
|
+
}>;
|
|
153
|
+
multiplierBps?: number;
|
|
154
|
+
}>;
|
|
177
155
|
/**
|
|
178
|
-
*
|
|
156
|
+
* Confirm that a given mint is currently staked by `wallet` in `poolId`.
|
|
179
157
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
158
|
+
* MUST return `false` for any mint not actively staked by the caller —
|
|
159
|
+
* otherwise a malicious client could submit a list of NFTs they do not own
|
|
160
|
+
* and have your server sign a bonus rate that the on-chain pool will accept.
|
|
183
161
|
*/
|
|
184
|
-
export type NftTraitResolver = (mint: string) => Promise<ReadonlyArray<{
|
|
185
|
-
traitType: string;
|
|
186
|
-
value: string;
|
|
187
|
-
}>>;
|
|
188
|
-
/** Validates which `requestedMints` are actually staked in `poolId` by `wallet`. */
|
|
189
162
|
export type StakedOwnershipResolver = (params: {
|
|
190
163
|
wallet: string;
|
|
191
|
-
poolId: number;
|
|
192
|
-
|
|
193
|
-
}) => Promise<
|
|
194
|
-
export
|
|
195
|
-
/**
|
|
164
|
+
poolId: number | bigint;
|
|
165
|
+
mint: string;
|
|
166
|
+
}) => Promise<boolean>;
|
|
167
|
+
export interface PrepareTraitProofInput {
|
|
168
|
+
/** Pool that will receive the claim. */
|
|
169
|
+
pool: PkInput;
|
|
170
|
+
/** Wallet doing the claim. */
|
|
171
|
+
wallet: PkInput;
|
|
172
|
+
/** Live `StakerAccount.totalClaimed` — read immediately before signing. */
|
|
173
|
+
totalClaimed: BnInput;
|
|
174
|
+
/** Pool id — only used for the ownership / stake-state lookup. */
|
|
175
|
+
poolId: number | bigint;
|
|
176
|
+
/**
|
|
177
|
+
* Collection mint configured on the pool (`StakePool.collectionMint`,
|
|
178
|
+
* base58). The catalog is fetched by this key so the same bonuses apply
|
|
179
|
+
* across every pool that stakes this collection. Pass an empty string for
|
|
180
|
+
* open-set pools (the store should return `[]`).
|
|
181
|
+
*/
|
|
182
|
+
collectionMint: string;
|
|
183
|
+
/** Mints the client claims to be staking. Each is verified individually. */
|
|
184
|
+
mints: string[];
|
|
185
|
+
store: TraitBonusStore;
|
|
186
|
+
resolveTraits: NftTraitResolver;
|
|
187
|
+
isStakedBy: StakedOwnershipResolver;
|
|
188
|
+
}
|
|
189
|
+
export interface PrepareTraitProofResult {
|
|
190
|
+
/** The 80-byte message ready for Ed25519 signing. */
|
|
191
|
+
message: Buffer;
|
|
192
|
+
/** Aggregated `u64` rate — pass to `claimRewards({ traitBonusRate })`. */
|
|
196
193
|
traitBonusRate: bigint;
|
|
197
|
-
/**
|
|
198
|
-
|
|
199
|
-
/** Mints the
|
|
194
|
+
/** Per-NFT breakdown, including mints that survived ownership verification. */
|
|
195
|
+
perNft: PerNftBonus[];
|
|
196
|
+
/** Mints that the client supplied but were rejected as not actively staked. */
|
|
200
197
|
rejectedMints: string[];
|
|
201
|
-
|
|
202
|
-
perNft: ComputeTraitBonusResult["perNft"];
|
|
203
|
-
/** Convenience: the raw 80-byte message to feed into `nacl.sign.detached`. */
|
|
204
|
-
message: Buffer;
|
|
205
|
-
};
|
|
198
|
+
}
|
|
206
199
|
/**
|
|
207
|
-
*
|
|
200
|
+
* Full backend orchestration: ownership-verify each mint, resolve traits,
|
|
201
|
+
* aggregate via `computeTraitBonusRate`, and build the signed message.
|
|
208
202
|
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* the
|
|
203
|
+
* The server is expected to sign `result.message` with the trait-authority
|
|
204
|
+
* Ed25519 keypair, return both the signature and `traitBonusRate` to the
|
|
205
|
+
* client, and the client forwards both into the `claimRewards` tx.
|
|
206
|
+
*/
|
|
207
|
+
export declare function prepareTraitProof(input: PrepareTraitProofInput): Promise<PrepareTraitProofResult>;
|
|
208
|
+
/**
|
|
209
|
+
* Adapter — turn an `NftStakingClient.fetchStakeEntriesByOwner` style call
|
|
210
|
+
* into a `StakedOwnershipResolver`. Pass in your already-constructed client.
|
|
212
211
|
*
|
|
213
|
-
* @example
|
|
214
212
|
* ```ts
|
|
215
|
-
*
|
|
216
|
-
* prepareTraitProof,
|
|
217
|
-
* type TraitBonusStore,
|
|
218
|
-
* } from "@soltracer/nft-staking"
|
|
219
|
-
*
|
|
220
|
-
* // 1) Implement the store against your DB once (any DB works).
|
|
221
|
-
* const traitBonusStore: TraitBonusStore = {
|
|
222
|
-
* async list({ poolId, projectId }) {
|
|
223
|
-
* const rows = await prisma.traitBonusConfig.findMany({
|
|
224
|
-
* where: { poolId, ...(projectId ? { projectId: String(projectId) } : {}) },
|
|
225
|
-
* })
|
|
226
|
-
* return rows.map((r) => ({
|
|
227
|
-
* traitType: r.traitType,
|
|
228
|
-
* value: r.traitValue,
|
|
229
|
-
* // pool is BaseMultiplier? use bonusBps. FixedExtra? use fixedExtra.
|
|
230
|
-
* bonusBps: r.bonusAmount,
|
|
231
|
-
* }))
|
|
232
|
-
* },
|
|
233
|
-
* }
|
|
234
|
-
*
|
|
235
|
-
* // 2) Prepare the proof on each claim request.
|
|
236
|
-
* const prepared = await prepareTraitProof({
|
|
237
|
-
* client, // NftStakingClient
|
|
238
|
-
* pool, // already-fetched StakePool (has rewardConfig + address)
|
|
239
|
-
* wallet: req.wallet,
|
|
240
|
-
* requestedMints: req.mints,
|
|
241
|
-
* store: traitBonusStore,
|
|
242
|
-
* resolveTraits: (mint) => catalog.getTraits(mint),
|
|
243
|
-
* })
|
|
244
|
-
*
|
|
245
|
-
* // 3) Sign and respond.
|
|
246
|
-
* const signature = nacl.sign.detached(prepared.message, traitAuthority.secretKey)
|
|
247
|
-
* return {
|
|
248
|
-
* traitBonusRate: prepared.traitBonusRate.toString(),
|
|
249
|
-
* signature: Buffer.from(signature).toString("base64"),
|
|
250
|
-
* perNft: prepared.perNft,
|
|
251
|
-
* rejectedMints: prepared.rejectedMints,
|
|
252
|
-
* }
|
|
213
|
+
* const isStakedBy = ownershipFromClient(client)
|
|
253
214
|
* ```
|
|
254
215
|
*/
|
|
255
|
-
export declare function prepareTraitProof(params: {
|
|
256
|
-
/** Pool config — must expose `address` and `rewardConfig.traitBonusMode`. */
|
|
257
|
-
pool: {
|
|
258
|
-
address: PkInput;
|
|
259
|
-
rewardConfig: {
|
|
260
|
-
traitBonusMode: number;
|
|
261
|
-
};
|
|
262
|
-
};
|
|
263
|
-
/** Project ID hint forwarded to the store (DB scoping, optional). */
|
|
264
|
-
projectId?: string | number;
|
|
265
|
-
poolId?: number;
|
|
266
|
-
wallet: PkInput;
|
|
267
|
-
requestedMints: ReadonlyArray<string>;
|
|
268
|
-
/** Storage adapter for the bonus catalog. */
|
|
269
|
-
store: TraitBonusStore;
|
|
270
|
-
/** Resolves trait list for a single mint. */
|
|
271
|
-
resolveTraits: NftTraitResolver;
|
|
272
|
-
/**
|
|
273
|
-
* Validates which `requestedMints` are actually staked in this pool by
|
|
274
|
-
* `wallet`. If omitted, the orchestrator trusts the caller — DO NOT skip
|
|
275
|
-
* this in production. The SDK can drive this for you when you pass a
|
|
276
|
-
* `client` and `poolId` (see `ownershipFromClient`).
|
|
277
|
-
*/
|
|
278
|
-
validateOwnership: StakedOwnershipResolver;
|
|
279
|
-
/**
|
|
280
|
-
* Current `StakerAccount.totalClaimed` nonce. MUST be the live value;
|
|
281
|
-
* advance-then-sign in the same request to avoid same-second replay.
|
|
282
|
-
*/
|
|
283
|
-
totalClaimed: BnInput;
|
|
284
|
-
}): Promise<PreparedTraitProof>;
|
|
285
|
-
/**
|
|
286
|
-
* Convenience `StakedOwnershipResolver` that uses an `NftStakingClient` to
|
|
287
|
-
* walk the wallet's stake entries and only allow mints currently staked in
|
|
288
|
-
* `poolId`. Wire this into `prepareTraitProof({ validateOwnership })` if you
|
|
289
|
-
* don't already have your own stake index.
|
|
290
|
-
*/
|
|
291
216
|
export declare function ownershipFromClient(client: {
|
|
292
|
-
fetchStakeEntriesByOwner: (
|
|
217
|
+
fetchStakeEntriesByOwner: (owner: PkInput, poolId?: number) => Promise<Array<{
|
|
218
|
+
poolId: number;
|
|
293
219
|
nftMint: {
|
|
294
220
|
toBase58(): string;
|
|
295
221
|
};
|
package/dist/traitProof.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traitProof.d.ts","sourceRoot":"","sources":["../src/traitProof.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"traitProof.d.ts","sourceRoot":"","sources":["../src/traitProof.ts"],"names":[],"mappings":"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"}
|