Staking NFTs
Staking an XPowerNft locks it in the NftTreasury and mints an APowerNft — a staking receipt that earns continuous APOW rewards proportional to your staked denomination, level, and duration.
Prerequisites
- One or more XPowerNfts in your wallet (see Depositing XPOW)
- AVAX for gas (~0.005–0.01 per stake transaction)
- The XPower app or direct contract access
Step-by-Step
1. Approve the NftTreasury to Handle Your NFTs
The NftTreasury needs permission to take custody of your XPowerNfts. Since XPowerNft is ERC-1155, use setApprovalForAll:
XPowerNft.setApprovalForAll(nftTreasuryAddress, true)This grants the NftTreasury blanket approval to transfer all your XPowerNfts. You only need to call this once — subsequent stakes reuse the same approval.
Gas cost: ~46,000.
Revoking Approval
If you later want to revoke the treasury's access, call setApprovalForAll(nftTreasuryAddress, false). Note that this does not affect already-staked NFTs — those are already held by the treasury and must be unstaked separately.
2. Stake Your NFTs
NftTreasury.stake(yourAddress, nftId, amount)Where:
yourAddressis the owner of the XPowerNfts (must bemsg.sender)nftIdis the token ID of the XPowerNft you're staking (e.g.,202603)amountis how many NFTs of this ID to stake
Example: staking 2 level-6 NFTs minted in 2026:
NftTreasury.stake("0xYour...", 202606, 2)Gas cost: ~150,000–250,000 (includes rate refresh, APowerNft mint, and storage updates).
3. Receive Your APowerNft
After the transaction confirms, you receive an APowerNft — an ERC-1155 staking receipt with the same token ID and amount. This APowerNft:
- Represents your staked position in the NftTreasury
- Accumulates age (time-weighted presence) used to calculate your APB bonus
- Is fully transferable (though age resets on transfer)
- Can be partially unstaked — you don't need to withdraw everything at once
4. Verify Your Stake
- Check your XPowerNft balance — it should decrease by the staked
amount - Check your APowerNft balance — it should increase by the staked
amountfor the samenftId - Verify on-chain: the
Stakeevent emitted by NftTreasury confirms the stake details - Your rewards begin accruing immediately from the block the stake is confirmed
What Happens Internally
When you call NftTreasury.stake(account, nftId, amount), a coordinated sequence executes across multiple contracts:
1. XPowerNft Custody
The NftTreasury calls XPowerNft.safeTransferFrom(account, nftTreasuryAddress, nftId, amount, ""). Your XPowerNft moves into the treasury's escrow balance. The treasury now holds the underlying claim on the locked XPOW.
2. APowerNft Minting
The NftTreasury calls APowerNft.mint(account, nftId, amount, age=0). A new APowerNft is created in your wallet with:
- Same ID and amount as the deposited XPowerNft — the 1:1 correspondence is preserved
- Age initialized to 0 — your holding period starts now
- Share totals updated — the
_shares[nftId]accumulator increases byamount * denomination, feeding into the dynamic rate scalar
Only the NftTreasury can mint APowerNfts (enforced via onlyOwner). Users cannot create them directly.
3. Rate Refresh
The NftTreasury calls MoeTreasury.refreshRates(false). This recomputes the dynamic scalar for every active level, redistributing the reward budget based on the new share distribution:
If your staked level was under-supplied, the scalar increases, boosting rewards for all stakers at that level. If over-supplied, the scalar decreases. The total reward budget is redistributed — it does not increase or decrease.
4. Event and State
The NftTreasury emits the Stake(account, nftId, amount) event. Storage is updated:
- NftTreasury's XPowerNft balance increases
- Your APowerNft balance increases
_shares[nftId]in MoeTreasury reflects the new stake- Dynamic scalars for all levels are refreshed
Partial Staking
You don't need to stake all your XPowerNfts of a given ID. If you hold 10 level-3 NFTs and only want to stake 3:
NftTreasury.stake(yourAddress, 202603, 3)The remaining 7 XPowerNfts stay in your wallet, fully transferable. You can stake them later, or leave them unstaked.
Conversely, you can add to an existing staked position. If you already have APowerNfts for ID 202603 and stake more, the new APowerNfts are minted with fresh age=0 while the existing ones retain their accumulated age.
Rate and Reward Context
Staking is the gateway to rewards. Once staked, your APowerNft begins accumulating:
- APR — a level-based base rate determined by a configurable polynomial
- APB — an age-based bonus that increases with your holding duration
- Dynamic scalar — adjusts your effective rate based on how popular your level is
The reward formula combines these factors:
Where
Gas Summary
| Action | Approx. Gas | Notes |
|---|---|---|
setApprovalForAll (one-time) | ~46,000 | Only needed once per wallet |
stake (single NFT) | ~150,000–250,000 | Includes rate refresh |
stake (batch, if supported) | Higher per NFT | Amortizes rate refresh overhead |
Next Steps
Once your NFTs are staked:
- Claiming APOW — collect your accumulated rewards
- Unstaking — withdraw your XPowerNfts when ready
- Upgrading NFTs — consolidate into higher tiers for greater rewards