@soltracer/nft-staking 0.3.0 → 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 +278 -55
- 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 +186 -120
- package/dist/traitProof.d.ts.map +1 -1
- package/dist/traitProof.js +120 -85
- package/dist/traitProof.js.map +1 -1
- package/package.json +2 -2
package/dist/idl.json
CHANGED
|
@@ -1565,7 +1565,7 @@
|
|
|
1565
1565
|
{
|
|
1566
1566
|
"name": "stake_config",
|
|
1567
1567
|
"docs": [
|
|
1568
|
-
"Global stake config
|
|
1568
|
+
"Global stake config — holds the platform's default trait authority."
|
|
1569
1569
|
],
|
|
1570
1570
|
"pda": {
|
|
1571
1571
|
"seeds": [
|
|
@@ -2638,7 +2638,7 @@
|
|
|
2638
2638
|
{
|
|
2639
2639
|
"name": "reward_vault",
|
|
2640
2640
|
"docs": [
|
|
2641
|
-
"Reward vault
|
|
2641
|
+
"Reward vault — required for token-reward pools. Must be drained before closure.",
|
|
2642
2642
|
"Pass the pool_authority ATA for the reward mint. Omit for SOL-reward pools."
|
|
2643
2643
|
],
|
|
2644
2644
|
"optional": true
|
|
@@ -2851,14 +2851,14 @@
|
|
|
2851
2851
|
{
|
|
2852
2852
|
"name": "reward_mint",
|
|
2853
2853
|
"docs": [
|
|
2854
|
-
"Reward mint
|
|
2854
|
+
"Reward mint — the token paid out as rewards (can be any SPL token).",
|
|
2855
2855
|
"Ignored if reward_type == Points."
|
|
2856
2856
|
]
|
|
2857
2857
|
},
|
|
2858
2858
|
{
|
|
2859
2859
|
"name": "reward_vault",
|
|
2860
2860
|
"docs": [
|
|
2861
|
-
"Reward vault ATA owned by pool_authority
|
|
2861
|
+
"Reward vault ATA owned by pool_authority — created for token rewards."
|
|
2862
2862
|
],
|
|
2863
2863
|
"writable": true,
|
|
2864
2864
|
"pda": {
|
|
@@ -6193,7 +6193,7 @@
|
|
|
6193
6193
|
{
|
|
6194
6194
|
"name": "sync_stake_entry_secondary",
|
|
6195
6195
|
"docs": [
|
|
6196
|
-
"re-sync one StakeEntry's contribution to",
|
|
6196
|
+
"STAKE-FRESH-2026-05-11 (F-H4): re-sync one StakeEntry's contribution to",
|
|
6197
6197
|
"`pool_secondary.rewards[secondary_index]`. Permissionless. Lets",
|
|
6198
6198
|
"existing stakers begin accruing on a secondary that was added",
|
|
6199
6199
|
"post-stake (or pick up a rate-update) without unstaking."
|
|
@@ -6383,7 +6383,7 @@
|
|
|
6383
6383
|
{
|
|
6384
6384
|
"name": "payer",
|
|
6385
6385
|
"docs": [
|
|
6386
|
-
"Permissionless
|
|
6386
|
+
"Permissionless — anyone may invoke. Pays no tx fee beyond signer",
|
|
6387
6387
|
"requirement and does not need to match the staker."
|
|
6388
6388
|
],
|
|
6389
6389
|
"signer": true
|
|
@@ -7310,7 +7310,7 @@
|
|
|
7310
7310
|
{
|
|
7311
7311
|
"name": "staker_nft_account",
|
|
7312
7312
|
"docs": [
|
|
7313
|
-
"User's NFT token account
|
|
7313
|
+
"User's NFT token account — destination for unstaked NFT."
|
|
7314
7314
|
],
|
|
7315
7315
|
"writable": true
|
|
7316
7316
|
},
|
|
@@ -8602,7 +8602,7 @@
|
|
|
8602
8602
|
{
|
|
8603
8603
|
"code": 6038,
|
|
8604
8604
|
"name": "UtilityNotActive",
|
|
8605
|
-
"msg": "Utility is not active for this project
|
|
8605
|
+
"msg": "Utility is not active for this project — check subscription status"
|
|
8606
8606
|
},
|
|
8607
8607
|
{
|
|
8608
8608
|
"code": 6039,
|
|
@@ -8636,56 +8636,61 @@
|
|
|
8636
8636
|
},
|
|
8637
8637
|
{
|
|
8638
8638
|
"code": 6045,
|
|
8639
|
+
"name": "PoolStillActive",
|
|
8640
|
+
"msg": "Pool must be deactivated (is_active = false) before it can be closed"
|
|
8641
|
+
},
|
|
8642
|
+
{
|
|
8643
|
+
"code": 6046,
|
|
8639
8644
|
"name": "SecondaryRewardRetired",
|
|
8640
8645
|
"msg": "Secondary reward is retired and cannot be modified"
|
|
8641
8646
|
},
|
|
8642
8647
|
{
|
|
8643
|
-
"code":
|
|
8648
|
+
"code": 6047,
|
|
8644
8649
|
"name": "SecondaryRewardAlreadyRetired",
|
|
8645
8650
|
"msg": "Secondary reward is already retired"
|
|
8646
8651
|
},
|
|
8647
8652
|
{
|
|
8648
|
-
"code":
|
|
8653
|
+
"code": 6048,
|
|
8649
8654
|
"name": "SecondaryRewardMintImmutable",
|
|
8650
|
-
"msg": "Secondary reward mint is immutable
|
|
8655
|
+
"msg": "Secondary reward mint is immutable — retire and add a new slot instead"
|
|
8651
8656
|
},
|
|
8652
8657
|
{
|
|
8653
|
-
"code":
|
|
8658
|
+
"code": 6049,
|
|
8654
8659
|
"name": "ClaimLockedUntilExpiry",
|
|
8655
|
-
"msg": "Mid-lock claims are disabled for this tier
|
|
8660
|
+
"msg": "Mid-lock claims are disabled for this tier — rewards are paid out at unstake"
|
|
8656
8661
|
},
|
|
8657
8662
|
{
|
|
8658
|
-
"code":
|
|
8663
|
+
"code": 6050,
|
|
8659
8664
|
"name": "StakerMismatch",
|
|
8660
8665
|
"msg": "Caller is not the staker for this entry"
|
|
8661
8666
|
},
|
|
8662
8667
|
{
|
|
8663
|
-
"code":
|
|
8668
|
+
"code": 6051,
|
|
8664
8669
|
"name": "LockTierConfigMissing",
|
|
8665
8670
|
"msg": "Lock tier config missing - pool was reconfigured with active entries"
|
|
8666
8671
|
},
|
|
8667
8672
|
{
|
|
8668
|
-
"code":
|
|
8673
|
+
"code": 6052,
|
|
8669
8674
|
"name": "NftAlreadyStaked",
|
|
8670
8675
|
"msg": "NFT is already staked"
|
|
8671
8676
|
},
|
|
8672
8677
|
{
|
|
8673
|
-
"code":
|
|
8678
|
+
"code": 6053,
|
|
8674
8679
|
"name": "UserBanned",
|
|
8675
8680
|
"msg": "User profile is banned"
|
|
8676
8681
|
},
|
|
8677
8682
|
{
|
|
8678
|
-
"code":
|
|
8683
|
+
"code": 6054,
|
|
8679
8684
|
"name": "UserProfileMismatch",
|
|
8680
8685
|
"msg": "User profile does not match staker"
|
|
8681
8686
|
},
|
|
8682
8687
|
{
|
|
8683
|
-
"code":
|
|
8688
|
+
"code": 6055,
|
|
8684
8689
|
"name": "InvalidQuantityBonus",
|
|
8685
8690
|
"msg": "Invalid quantity bonus configuration"
|
|
8686
8691
|
},
|
|
8687
8692
|
{
|
|
8688
|
-
"code":
|
|
8693
|
+
"code": 6056,
|
|
8689
8694
|
"name": "BaseStakingDisabled",
|
|
8690
8695
|
"msg": "Unlocked/base staking is disabled for this pool"
|
|
8691
8696
|
}
|
|
@@ -8758,7 +8763,7 @@
|
|
|
8758
8763
|
{
|
|
8759
8764
|
"name": "claim_only_at_end",
|
|
8760
8765
|
"docs": [
|
|
8761
|
-
"If true, mid-lock claims are blocked
|
|
8766
|
+
"If true, mid-lock claims are blocked — rewards are only accessible at unstake.",
|
|
8762
8767
|
"Ensures the early-unstake penalty cannot be bypassed by claiming before unstaking."
|
|
8763
8768
|
],
|
|
8764
8769
|
"type": "bool"
|
|
@@ -8854,7 +8859,7 @@
|
|
|
8854
8859
|
"name": "PoolSecondaryRewards",
|
|
8855
8860
|
"docs": [
|
|
8856
8861
|
"Separate PDA holding secondary reward configs for a pool.",
|
|
8857
|
-
"Exists only when the pool has secondary rewards
|
|
8862
|
+
"Exists only when the pool has secondary rewards — zero migration needed."
|
|
8858
8863
|
],
|
|
8859
8864
|
"type": {
|
|
8860
8865
|
"kind": "struct",
|
|
@@ -8876,7 +8881,7 @@
|
|
|
8876
8881
|
{
|
|
8877
8882
|
"name": "is_initialized",
|
|
8878
8883
|
"docs": [
|
|
8879
|
-
"Explicit init sentinel
|
|
8884
|
+
"Explicit init sentinel — avoids ambiguous pool_id == 0 check for pool 0 (STAKE-H1)"
|
|
8880
8885
|
],
|
|
8881
8886
|
"type": "bool"
|
|
8882
8887
|
},
|
|
@@ -8937,12 +8942,16 @@
|
|
|
8937
8942
|
"type": "i64"
|
|
8938
8943
|
},
|
|
8939
8944
|
{
|
|
8940
|
-
"name": "
|
|
8945
|
+
"name": "trait_bonus_enabled",
|
|
8941
8946
|
"docs": [
|
|
8942
|
-
"
|
|
8943
|
-
"
|
|
8947
|
+
"When `true`, the pool accepts a signed `trait_bonus_rate` from the",
|
|
8948
|
+
"configured trait authority on every claim. The signed `u64` is added",
|
|
8949
|
+
"directly to the staker's effective rate for the accrual window —",
|
|
8950
|
+
"projects compute per-trait math (including any per-NFT multipliers)",
|
|
8951
|
+
"off-chain and sign the final absolute extra rate. When `false`, any",
|
|
8952
|
+
"non-zero `trait_bonus_rate` is rejected on-chain."
|
|
8944
8953
|
],
|
|
8945
|
-
"type": "
|
|
8954
|
+
"type": "bool"
|
|
8946
8955
|
},
|
|
8947
8956
|
{
|
|
8948
8957
|
"name": "quantity_thresholds",
|
|
@@ -9025,7 +9034,7 @@
|
|
|
9025
9034
|
{
|
|
9026
9035
|
"name": "retired_at",
|
|
9027
9036
|
"docs": [
|
|
9028
|
-
"unix timestamp at which the slot was",
|
|
9037
|
+
"STAKE-FRESH-2026-05-11 (F-H3): unix timestamp at which the slot was",
|
|
9029
9038
|
"retired. `0` while active. Used by `accrue_secondary` /",
|
|
9030
9039
|
"`accrue_and_sub_secondary` to cap per-staker accrual at the moment of",
|
|
9031
9040
|
"retirement so the time window between a staker's last interaction and",
|
|
@@ -9068,7 +9077,7 @@
|
|
|
9068
9077
|
{
|
|
9069
9078
|
"name": "StakeEntry",
|
|
9070
9079
|
"docs": [
|
|
9071
|
-
"Per-NFT custody and lock tracking. No reward fields
|
|
9080
|
+
"Per-NFT custody and lock tracking. No reward fields — rewards are",
|
|
9072
9081
|
"accumulated on the parent StakerAccount via `effective_rate`."
|
|
9073
9082
|
],
|
|
9074
9083
|
"type": {
|
|
@@ -9131,7 +9140,7 @@
|
|
|
9131
9140
|
{
|
|
9132
9141
|
"name": "early_unstake_penalty_bps",
|
|
9133
9142
|
"docs": [
|
|
9134
|
-
"early-unstake penalty (bps) captured at",
|
|
9143
|
+
"STAKE2-M3 (audit 2026-05-05): early-unstake penalty (bps) captured at",
|
|
9135
9144
|
"stake time. Read at unstake instead of `pool.lock_configs[tier].early_unstake_penalty_bps`",
|
|
9136
9145
|
"so the authority cannot retroactively raise the penalty after the",
|
|
9137
9146
|
"staker has committed. Zero when the entry has no lock."
|
|
@@ -9144,7 +9153,7 @@
|
|
|
9144
9153
|
{
|
|
9145
9154
|
"name": "StakeEntrySecondarySynced",
|
|
9146
9155
|
"docs": [
|
|
9147
|
-
"emitted when a StakeEntry's",
|
|
9156
|
+
"STAKE-FRESH-2026-05-11 (F-H4): emitted when a StakeEntry's",
|
|
9148
9157
|
"secondary_rate_contributions[index] is re-synced to the pool's current",
|
|
9149
9158
|
"config (e.g. after an admin added a new secondary slot post-stake)."
|
|
9150
9159
|
],
|
|
@@ -9309,7 +9318,7 @@
|
|
|
9309
9318
|
{
|
|
9310
9319
|
"name": "total_effective_rate",
|
|
9311
9320
|
"docs": [
|
|
9312
|
-
"aggregate of every active staker's",
|
|
9321
|
+
"STAKE-FRESH-2026-05-11 (F-H1): aggregate of every active staker's",
|
|
9313
9322
|
"`effective_rate`. Maintained at every stake/unstake/burn site.",
|
|
9314
9323
|
"Used by [`pool_settle`] to advance obligation for stakers who have",
|
|
9315
9324
|
"not yet visited the pool since `last_pool_accrual_ts`."
|
|
@@ -9319,7 +9328,7 @@
|
|
|
9319
9328
|
{
|
|
9320
9329
|
"name": "last_pool_accrual_ts",
|
|
9321
9330
|
"docs": [
|
|
9322
|
-
"unix timestamp at which the pool's",
|
|
9331
|
+
"STAKE-FRESH-2026-05-11 (F-H1): unix timestamp at which the pool's",
|
|
9323
9332
|
"total obligation was last advanced. Bumped by every handler that",
|
|
9324
9333
|
"touches the pool (via [`pool_settle`])."
|
|
9325
9334
|
],
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { NftStakingClient, type FeeParams, type NftRewardAmount, type NftRewardSummary, type NftRewardSummaryOptions, } from "./client";
|
|
2
|
-
export { NFT_STAKING_PROGRAM_ID, getStakeConfigPda, getStakePoolPda, getStakeEntryPda, getStakerAccountPda, getCollectionPda, getPoolAuthorityPda, getPoolSecondaryRewardsPda, getStakerSecondaryRewardsPda, StakingMode, NftStandard, RewardType,
|
|
2
|
+
export { NFT_STAKING_PROGRAM_ID, getStakeConfigPda, getStakePoolPda, getStakeEntryPda, getStakerAccountPda, getCollectionPda, getPoolAuthorityPda, getPoolSecondaryRewardsPda, getStakerSecondaryRewardsPda, StakingMode, NftStandard, RewardType, } from "@soltracer/core";
|
|
3
3
|
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,
|
|
7
|
+
export { buildTraitProofMessage, TRAIT_PROOF_MSG_LEN, computeTraitBonusRate, prepareTraitProof, ownershipFromClient, InMemoryTraitBonusStore, type TraitBonusCatalogEntry, type NftTraitInput, type PerNftBonus, type TraitBonusComputation, type TraitBonusStore, type NftTraitResolver, type StakedOwnershipResolver, type PrepareTraitProofInput, type PrepareTraitProofResult, } 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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,GACX,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,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { NftStakingClient, } from "./client";
|
|
2
|
-
export { NFT_STAKING_PROGRAM_ID, getStakeConfigPda, getStakePoolPda, getStakeEntryPda, getStakerAccountPda, getCollectionPda, getPoolAuthorityPda, getPoolSecondaryRewardsPda, getStakerSecondaryRewardsPda, StakingMode, NftStandard, RewardType,
|
|
2
|
+
export { NFT_STAKING_PROGRAM_ID, getStakeConfigPda, getStakePoolPda, getStakeEntryPda, getStakerAccountPda, getCollectionPda, getPoolAuthorityPda, getPoolSecondaryRewardsPda, getStakerSecondaryRewardsPda, StakingMode, NftStandard, RewardType, } from "@soltracer/core";
|
|
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,
|
|
6
|
+
export { buildTraitProofMessage, TRAIT_PROOF_MSG_LEN, computeTraitBonusRate, prepareTraitProof, ownershipFromClient, InMemoryTraitBonusStore, } 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,
|
|
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,GACX,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,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,GAUxB,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"}
|
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
|
-
*
|
|
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.
|
|
7
13
|
*
|
|
8
|
-
*
|
|
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,125 +49,176 @@ export declare function buildTraitProofMessage(params: {
|
|
|
34
49
|
totalClaimed: BnInput;
|
|
35
50
|
}): Buffer;
|
|
36
51
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* import { Ed25519Program } from "@solana/web3.js"
|
|
42
|
-
* import { buildTraitProofMessage } from "@soltracer/nft-staking"
|
|
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.
|
|
43
56
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
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
|
-
* ```
|
|
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".
|
|
59
60
|
*/
|
|
61
|
+
export interface TraitBonusCatalogEntry {
|
|
62
|
+
traitType: string;
|
|
63
|
+
value: string;
|
|
64
|
+
/** Raw reward units per `rateInterval` to add for this trait. */
|
|
65
|
+
bonus: bigint;
|
|
66
|
+
}
|
|
60
67
|
/**
|
|
61
|
-
*
|
|
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`.
|
|
68
|
+
* Storage-agnostic store interface — implement with Prisma, Drizzle, Firestore,
|
|
69
|
+
* in-memory, etc.
|
|
90
70
|
*
|
|
91
|
-
* Catalog
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
|
|
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<{
|
|
103
|
+
traitType: string;
|
|
104
|
+
value: string;
|
|
105
|
+
}>;
|
|
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`. */
|
|
123
|
+
traitBonusRate: bigint;
|
|
124
|
+
/** Per-NFT breakdown — useful for surfacing "you earned X from this NFT" in UI. */
|
|
125
|
+
perNft: PerNftBonus[];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Aggregate trait bonuses into a single absolute `u64` rate.
|
|
97
129
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
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
|
-
* })
|
|
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.)
|
|
110
135
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* totalClaimed: stakerAccount.totalClaimed,
|
|
115
|
-
* })
|
|
116
|
-
* ```
|
|
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.
|
|
117
139
|
*/
|
|
118
|
-
export
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
export type
|
|
127
|
-
|
|
128
|
-
/** Ordered or unordered list of an NFT's traits, after ownership validation. */
|
|
129
|
-
traits: ReadonlyArray<{
|
|
140
|
+
export declare function computeTraitBonusRate(params: {
|
|
141
|
+
catalog: TraitBonusCatalogEntry[];
|
|
142
|
+
nfts: NftTraitInput[];
|
|
143
|
+
}): TraitBonusComputation;
|
|
144
|
+
/**
|
|
145
|
+
* Resolve the trait list for a staked mint. Implementations typically read
|
|
146
|
+
* from off-chain metadata, an indexer, or a cached project DB.
|
|
147
|
+
*/
|
|
148
|
+
export type NftTraitResolver = (mint: string) => Promise<{
|
|
149
|
+
traits: Array<{
|
|
130
150
|
traitType: string;
|
|
131
151
|
value: string;
|
|
132
152
|
}>;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
multiplierBps?: number;
|
|
154
|
+
}>;
|
|
155
|
+
/**
|
|
156
|
+
* Confirm that a given mint is currently staked by `wallet` in `poolId`.
|
|
157
|
+
*
|
|
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.
|
|
161
|
+
*/
|
|
162
|
+
export type StakedOwnershipResolver = (params: {
|
|
163
|
+
wallet: string;
|
|
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 })`. */
|
|
136
193
|
traitBonusRate: bigint;
|
|
137
|
-
/** Per-NFT breakdown
|
|
138
|
-
perNft:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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. */
|
|
197
|
+
rejectedMints: string[];
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Full backend orchestration: ownership-verify each mint, resolve traits,
|
|
201
|
+
* aggregate via `computeTraitBonusRate`, and build the signed message.
|
|
202
|
+
*
|
|
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>;
|
|
149
208
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
209
|
+
* Adapter — turn an `NftStakingClient.fetchStakeEntriesByOwner` style call
|
|
210
|
+
* into a `StakedOwnershipResolver`. Pass in your already-constructed client.
|
|
211
|
+
*
|
|
212
|
+
* ```ts
|
|
213
|
+
* const isStakedBy = ownershipFromClient(client)
|
|
214
|
+
* ```
|
|
153
215
|
*/
|
|
154
|
-
export declare function
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
216
|
+
export declare function ownershipFromClient(client: {
|
|
217
|
+
fetchStakeEntriesByOwner: (owner: PkInput, poolId?: number) => Promise<Array<{
|
|
218
|
+
poolId: number;
|
|
219
|
+
nftMint: {
|
|
220
|
+
toBase58(): string;
|
|
221
|
+
};
|
|
222
|
+
}>>;
|
|
223
|
+
}): StakedOwnershipResolver;
|
|
158
224
|
//# sourceMappingURL=traitProof.d.ts.map
|
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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"}
|