Minting and Upgrading
XPowerNfts are created by depositing XPOW tokens and can be consolidated into higher-tier NFTs through the upgrade mechanism. This page covers the complete lifecycle of NFT creation, destruction, and tier progression.
Minting
Minting converts XPOW into an XPowerNft. The user must first approve the XPowerNft contract to spend their XPOW via the ERC20 approve mechanism.
Single Mint
function mint(address account, uint256 level, uint256 amount) externalParameters:
account— recipient of the minted NFTs (must bemsg.senderor an approved minter)level— the tier level (must be a multiple of 3,0 ≤ level < 100)amount— number of NFTs to mint at this level
Process:
- Authorization:
require(account == msg.sender || approvedMint(account, msg.sender)) - XPOW deposit:
XPower.transferFrom(account, this, amount × 10^level × 10^18) - NFT mint:
_mint(account, idBy(year(), level), amount, "")
Example: Minting 5 level-3 NFTs in 2026:
- XPOW cost:
5 × 10^3= 5,000 XPOW transferred from user - NFTs received: 5 ×
id=202603(XPowerNft at level 3, mint year 2026) - Each NFT represents 1,000 XPOW
Batch Mint
function mintBatch(address account, uint256[] memory levels, uint256[] memory amounts) externalMints multiple levels in a single transaction. The total XPOW cost is the sum of amounts[i] × 10^levels[i], transferred in one transferFrom call.
Example: Minting both level-0 and level-6 NFTs in one transaction:
levels = [0, 6],amounts = [100, 2]- XPOW cost:
100 × 1 + 2 × 1,000,000= 2,000,100 XPOW - NFTs received: 100 ×
id=202600+ 2 ×id=202606
Batch minting saves gas by consolidating multiple mints into a single XPOW transfer.
Minting Approvals
Users can delegate minting authority to another address:
function approveMint(address operator, bool approved) externalThis is separate from ERC1155 transfer approvals. A use case: a contract or relay service that mints NFTs on a user's behalf without needing custody of their XPOW.
Burning and Redemption
Burning destroys an XPowerNft and releases its underlying XPOW back to the holder — but only if the NFT has reached maturity.
Single Burn
function burn(address account, uint256 id, uint256 amount) public overrideProcess:
- Maturity check:
require(yearOf(id) + 2^(levelOf(id)/3) - 1 <= year()) - ERC1155 burn:
_burn(account, id, amount) - XPOW release:
XPower.transfer(account, amount × denominationOf(levelOf(id)) × 10^18)
If the NFT has not yet matured, the transaction reverts with IrredeemableIssue(id).
Example: Burning 3 level-6 NFTs minted in 2026 (matures 2029):
- In 2030: maturity check passes, 3 × 1,000,000 = 3,000,000 XPOW released
- In 2028: maturity check fails, transaction reverts
Batch Burn
function burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) public overrideBurns multiple token IDs in a single transaction. All IDs must have passed their respective maturity dates — the function checks all IDs upfront and reverts if any are still immature.
Gas note: Batch burns are particularly efficient for unwinding diversified NFT positions. Instead of
Upgrading
Upgrading consolidates lower-level NFTs into higher-level ones at a fixed 1,000:1 ratio. This is the mechanism by which users progress through the tier system without needing additional XPOW.
The Upgrade Ratio
The core invariant:
This preserves XPOW value because:
Single Upgrade
function upgrade(address account, uint256 anno, uint256 level, uint256 amount) externalParameters:
account— owner of the NFTs (must bemsg.senderor approved)anno— the year of the source NFTs (must match the NFTs being upgraded)level— target level after upgrade (must be ≥ 3, i.e., a multiple of 3 greater than 0)amount— number of upgraded NFTs to produce at the target level
Process:
- Authorization:
require(account == msg.sender || approvedUpgrade(account, msg.sender)) - Level validation:
require(level > 2)(must be at least 3) - Burn source:
_burn(account, idBy(anno, level-3), amount × 1000) - Mint target:
_mint(account, idBy(anno, level), amount, "")
Example 1: Clean upgrade
- User holds 3,000 level-3 NFTs (id=202603)
- Calls
upgrade(user, 2026, 6, 3) - 3,000 level-3 NFTs are burned
- 3 level-6 NFTs (id=202606) are minted
- Total XPOW value unchanged:
Example 2: Partial upgrade
- User holds 2,500 level-3 NFTs
- Calls
upgrade(user, 2026, 6, 2) - 2,000 level-3 NFTs are burned (amount × 1000 = 2 × 1000)
- 2 level-6 NFTs are minted
- Remaining: 500 level-3 NFTs still held by user
Important: Upgrades always use the same year for source and target. You cannot upgrade a 2026 level-3 into a 2027 level-6 — the year parameter is shared, preserving the mint vintage.
Batch Upgrade
function upgradeBatch(
address account,
uint256[] memory annos,
uint256[][] memory levels,
uint256[][] memory amounts
) externalPerforms multiple upgrades across different years and target levels in a single transaction.
Parameters:
annos— array of years, one per upgrade grouplevels— 2D array:levels[i]is the array of target levels for yearannos[i]amounts— 2D array:amounts[i][j]is the amount for target levellevels[i][j]
The function processes upgrades group by group: for each year, it burns all source NFTs (at level-3 for each target level, multiplied by 1000) and mints all target NFTs. This uses _burnBatch and _mintBatch internally for gas efficiency.
Upgrade Approvals
Like minting, upgrading supports delegated execution:
function approveUpgrade(address operator, bool approved) externalA contract or service can be authorized to perform upgrades on a user's behalf. This is separate from minting and transfer approvals — each operation type has its own approval mapping.
Gas Considerations
Minting
- Base cost: ERC20
transferFrom+ ERC1155_mintper token ID - Batch mint reduces XPOW transfers to 1 (instead of 1 per level), saving ~20k–50k gas per additional level
Burning
- Each ID requires a maturity check (constant-time:
yearOf,levelOf, exponentiation) - Batch burn combines all XPOW releases into a single transfer, saving gas proportional to the number of IDs
Upgrading
- Each upgrade burns
amount × 1000source NFTs, meaning gas costs scale linearly with the number of source NFTs - Upgrading 1,000 level-3 → 1 level-6 costs roughly the same as burning 1,000 NFTs plus minting 1
- Upgrading 1,000,000 level-0 → 1 level-18 requires burning 1,000,000 NFTs — gas-prohibitive. Users should mint at intermediate levels when possible.
Optimization Strategies
| Strategy | Gas Saved |
|---|---|
Use mintBatch for multi-level deposits | ~30k per extra level |
Use burnBatch for multi-ID redemptions | ~25k per extra ID |
| Mint at target level directly instead of upgrading | Eliminates all upgrade gas |
Coalesce multiple upgrades into upgradeBatch | Amortizes per-transaction overhead |
Error Conditions
| Error | Condition |
|---|---|
NonTernaryLevel(level) | Level is not a multiple of 3 |
InvalidLevel(level) | Level ≥ 100 |
InvalidYear(anno) | Year ≤ 2020 |
IrredeemableIssue(id) | NFT has not reached maturity |
UnauthorizedAccount(account) | Caller is not the owner or an approved operator |
SelfApproving(operator) | User attempted to self-approve |
Complete Lifecycle Example
A user with 3,000,000 XPOW in 2026:
Step 1: Mint 3 × level-6 NFTs
→ approve(XPowerNft, 3,000,000)
→ mint(self, 6, 3)
→ Receives 3 × id=202606 (each worth 1M XPOW)
Step 2: Wait until 2029 (maturity year for level 6 = 2026 + 3)
→ burn(self, 202606, 2)
→ 2,000,000 XPOW released, 1 NFT remains
Step 3: Upgrade remaining level-6
→ Cannot — need 1,000 level-6 to upgrade to level-9
→ Burn final NFT: burn(self, 202606, 1)
→ Remaining 1,000,000 XPOW releasedRelated Reading
- Levels and Denominations — full level table and denomination math
- Redemption Maturity — how maturity lock periods work
- NFT System Overview — architecture and contract ownership