Skip to content

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 ​

solidity
function mint(address account, uint256 level, uint256 amount) external

Parameters:

  • account — recipient of the minted NFTs (must be msg.sender or 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:

  1. Authorization: require(account == msg.sender || approvedMint(account, msg.sender))
  2. XPOW deposit: XPower.transferFrom(account, this, amount × 10^level × 10^18)
  3. 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 ​

solidity
function mintBatch(address account, uint256[] memory levels, uint256[] memory amounts) external

Mints 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:

solidity
function approveMint(address operator, bool approved) external

This 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 ​

solidity
function burn(address account, uint256 id, uint256 amount) public override

Process:

  1. Maturity check: require(yearOf(id) + 2^(levelOf(id)/3) - 1 <= year())
  2. ERC1155 burn: _burn(account, id, amount)
  3. 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 ​

solidity
function burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) public override

Burns 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 n separate transactions (each with its own XPOW transfer), a single batch burn performs one combined XPOW transfer for the total.

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:

1,000 NFTs at level ℓ⟶1 NFT at level ℓ+3

This preserves XPOW value because:

1,000×10ℓ=103×10ℓ=10ℓ+3

Single Upgrade ​

solidity
function upgrade(address account, uint256 anno, uint256 level, uint256 amount) external

Parameters:

  • account — owner of the NFTs (must be msg.sender or 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:

  1. Authorization: require(account == msg.sender || approvedUpgrade(account, msg.sender))
  2. Level validation: require(level > 2) (must be at least 3)
  3. Burn source: _burn(account, idBy(anno, level-3), amount × 1000)
  4. 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: 3,000×103=3×106=3,000,000

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 ​

solidity
function upgradeBatch(
    address account,
    uint256[] memory annos,
    uint256[][] memory levels,
    uint256[][] memory amounts
) external

Performs multiple upgrades across different years and target levels in a single transaction.

Parameters:

  • annos — array of years, one per upgrade group
  • levels — 2D array: levels[i] is the array of target levels for year annos[i]
  • amounts — 2D array: amounts[i][j] is the amount for target level levels[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:

solidity
function approveUpgrade(address operator, bool approved) external

A 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 _mint per 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 × 1000 source 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 ​

StrategyGas 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 upgradingEliminates all upgrade gas
Coalesce multiple upgrades into upgradeBatchAmortizes per-transaction overhead

Error Conditions ​

ErrorCondition
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 released