Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PowerPass

Git Source

Inherits: Initializable, ERC721Upgradeable, ERC721URIStorageUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable, IPowerPass

Title: PowerPass - ShareX Ecosystem Premium Access NFT

Author: ShareX Team

Upgradeable ERC721 contract with time-based whitelist sales rounds PowerPass implements sophisticated whitelist-based sales with two rounds:

  • Priority Round: Exclusive access for MAGNA/NOVA stakers
  • General Round: Access for all ShareX Keys stakers Features:
  • Gas-optimized struct packing and unchecked arithmetic
  • Snapshot-based whitelist eligibility tied to ShareXKeysStaking
  • Admin-configurable sales rounds and pricing
  • Upgradeable proxy pattern for future enhancements
  • Comprehensive validation and error handling

State Variables

MAX_SUPPLY

Maximum supply of PowerPass NFTs

uint256 public constant MAX_SUPPLY = 5000

BPS_DENOMINATOR

Basis points denominator for discount calculations

uint16 private constant BPS_DENOMINATOR = 10_000

NOVA_DISCOUNT_BPS

Nova discount expressed in basis points (80%)

uint16 private constant NOVA_DISCOUNT_BPS = 8_000

MAX_NOVA_DISCOUNT_PER_ADDRESS

Maximum number of discounted NFTs per address for Nova holders

uint64 private constant MAX_NOVA_DISCOUNT_PER_ADDRESS = 10

_paymentToken

ERC20 payment token (e.g., USDT on BSC)

IERC20 private _paymentToken

MINTER_ROLE

Optional direct mint role for operational tooling

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE")

_currentRoundId

Current active round ID (starts from 1, 0 = no round started)

uint64 private _currentRoundId

_roundConfigs

Round configurations: roundId => RoundConfig

mapping(uint64 roundId => PowerPassRoundConfig config) private _roundConfigs

_roundWhitelists

Round whitelists: roundId => user => WhitelistInfo

mapping(uint64 roundId => mapping(address user => PowerPassWhitelistInfo whitelist)) private
    _roundWhitelists

_custodialWhitelists

Custodial whitelist allocations for ShareX wallet flow (independent of rounds)

mapping(address account => PowerPassCustodialWhitelistInfo whitelist) private
    _custodialWhitelists

_baseTokenURI

Base URI for token metadata

string private _baseTokenURI

_discountCodes

Active discount code hashes

mapping(bytes32 codeHash => bool isActive) private _discountCodes

_totalSupply

Current token supply

uint256 private _totalSupply

_currentTokenId

Current token ID counter

uint256 private _currentTokenId

_web3MintedCount

Web3 channel minted count (via public mint function)

uint256 private _web3MintedCount

_custodialMintedCount

Custodial/Web2 channel minted count (via MINTER_ROLE)

uint256 private _custodialMintedCount

_discountCodeUsageCount

Discount code usage count: codeHash => number of NFTs minted using this code

mapping(bytes32 codeHash => uint256 usageCount) private _discountCodeUsageCount

__gap

Storage gap for upgrade safety

uint256[30] private __gap

Functions

validAddress

Modifier to validate non-zero addresses

modifier validAddress(address addr) ;

validAmount

Modifier to validate non-zero amounts

modifier validAmount(uint256 amount) ;

initialize

Initialize the PowerPass contract

Replaces constructor for upgradeable pattern

function initialize(address _admin, string calldata baseURI_)
    external
    initializer
    validAddress(_admin);

Parameters

NameTypeDescription
_adminaddressAddress to grant admin role to
baseURI_stringBase URI for token metadata

initializeWithToken

Initialize with admin, baseURI and payment token

function initializeWithToken(address _admin, string calldata baseURI_, address paymentToken_)
    external
    initializer
    validAddress(_admin)
    validAddress(paymentToken_);

Parameters

NameTypeDescription
_adminaddressAddress to grant admin role to
baseURI_stringBase URI for token metadata
paymentToken_addressERC20 token used for payments (e.g., USDT)

startNewRound

Start a new sales round with configuration and supply limit

Admin function to create a new round; increments roundId automatically

function startNewRound(SalesConfig calldata config, uint256 supplyLimit)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
configSalesConfigSales configuration including timestamps and pricing
supplyLimituint256Maximum NFTs for this round (0 = no limit, still capped by MAX_SUPPLY) Requirements: - Caller must have DEFAULT_ADMIN_ROLE - Priority round must end before or when general round starts - All timestamps must be future timestamps (> block.timestamp) - Standard price must be greater than 0 Emits: PowerPassNewRoundStarted event

setPaymentToken

Set ERC20 payment token address (e.g., USDT on BSC)

Admin function; price is interpreted in this token's decimals

function setPaymentToken(address token) external override onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
tokenaddressERC20 token address used for payments

setDiscountCodeDiscount

Set discount code discount amount for current round

Updates discountCodeDiscount in current round config

function setDiscountCodeDiscount(uint256 discountAmount)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
discountAmountuint256New discount amount per NFT

addDiscountCodes

Register discount code hashes that can be redeemed on-chain

function addDiscountCodes(bytes32[] calldata codeHashes)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
codeHashesbytes32[]Array of keccak256 hashes of discount codes

removeDiscountCodes

Remove discount code hashes

function removeDiscountCodes(bytes32[] calldata codeHashes)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
codeHashesbytes32[]Array of keccak256 hashes of discount codes to remove

isDiscountCodeValid

Check if discount code hash is currently active

function isDiscountCodeValid(bytes32 codeHash) external view override returns (bool);

Parameters

NameTypeDescription
codeHashbytes32keccak256 hash of the off-chain discount code

getDiscountCodeUsageCount

Get the usage count for a specific discount code

Only counts usage when discount code is actually applied (excludes Nova discount cases)

function getDiscountCodeUsageCount(bytes32 codeHash) external view override returns (uint256);

Parameters

NameTypeDescription
codeHashbytes32keccak256 hash of the discount code

Returns

NameTypeDescription
<none>uint256usageCount Number of NFTs minted using this discount code

mint

Mint PowerPass NFTs during active sales rounds

Gas-optimized minting with comprehensive validation

function mint(uint256 amount, string calldata discountCode)
    external
    payable
    override
    nonReentrant
    validAmount(amount);

Parameters

NameTypeDescription
amountuint256Number of NFTs to mint
discountCodestringOptional discount code string; ignored when empty or Nova discount applies Validation includes: - Active sales round verification (priority or general) - Whitelist allocation and remaining balance checks - Payment in ERC20 payment token (e.g., USDT) equals applicable discounted price * amount - Maximum supply limit enforcement Requirements: - Active sales round (priority or general) must be ongoing - Amount must not exceed remaining allocation for current round - Payment must be provided via ERC20 approve + transferFrom - User must have whitelist allocation for current round Emits: PowerPassBatchMinted event

_calculateTotalPrice

Calculate total price with Nova and discount code discounts

function _calculateTotalPrice(
    PowerPassRoundConfig storage roundConfig,
    uint256 amount,
    uint256 novaEligible,
    string calldata discountCode
) private returns (uint256 totalPrice);

Parameters

NameTypeDescription
roundConfigPowerPassRoundConfigRound configuration containing prices
amountuint256Total amount to mint
novaEligibleuint256Amount eligible for Nova discount
discountCodestringDiscount code string

Returns

NameTypeDescription
totalPriceuint256Final price after discounts

batchSetWhitelists

Batch set whitelist allocations for multiple users

Admin function for efficient whitelist management. Preserves already minted counts and clamps new allocations to be >= minted so far for each round.

function batchSetWhitelists(
    address[] calldata accounts,
    uint256[] calldata priorityAmounts,
    uint256[] calldata generalAmounts
) external override onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
accountsaddress[]Array of addresses to set allocations for
priorityAmountsuint256[]Array of priority allocations corresponding to accounts
generalAmountsuint256[]Array of total (priority + general) allocations corresponding to accounts Requirements: - Caller must have DEFAULT_ADMIN_ROLE - All arrays must have equal length - No account can be zero address - Never reduces effective allocation below already minted amounts - Gas-optimized with unchecked arithmetic for large batches Emits: PowerPassBatchWhitelistSet event

batchSetNovaDiscounts

Batch set Nova discount allocations for multiple users

Admin function to configure 80% pricing eligibility per address

function batchSetNovaDiscounts(
    address[] calldata accounts,
    uint256[] calldata discountAllocations
) external override onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
accountsaddress[]Array of addresses to configure
discountAllocationsuint256[]Array of discount allocations corresponding to accounts

batchSetCustodialWhitelists

Batch set custodial mint allocations for ShareX wallet users

Separate whitelist for web2 custodial flow; amounts represent direct mint allowance

function batchSetCustodialWhitelists(
    address[] calldata accounts,
    uint256[] calldata allocations
) external override onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
accountsaddress[]Custodial wallet addresses (ShareX wallet addresses or end-user custodial addrs)
allocationsuint256[]Total NFTs each address may receive via custodial mint

setBaseURI

Set the base URI for token metadata

Admin function to configure NFT metadata URIs

function setBaseURI(string calldata baseURI) external override onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
baseURIstringThe new base URI for all tokens Requirements: - Caller must have DEFAULT_ADMIN_ROLE - BaseURI should point to valid metadata endpoint Emits: PowerPassBaseURIUpdated event

withdrawFunds

Withdraw payment tokens to admin

Admin function to withdraw accumulated ERC20 (USDT) from sales Requirements:

  • Caller must have DEFAULT_ADMIN_ROLE
  • Contract must have token balance > 0 Emits: PowerPassFundsWithdrawn event
function withdrawFunds() external override onlyRole(DEFAULT_ADMIN_ROLE);

paymentToken

Get ERC20 payment token address

function paymentToken() external view override returns (address);

mint

Direct mint by operators with MINTER_ROLE

function mint(address to, string calldata tokenURI_)
    external
    onlyRole(MINTER_ROLE)
    returns (uint256 tokenId);

mint

Direct mint by operators with MINTER_ROLE using automatic token URI formatting

function mint(address to) external onlyRole(MINTER_ROLE) returns (uint256 tokenId);

burn

Burn a token (legacy compatibility)

function burn(uint256 tokenId) external;

Parameters

NameTypeDescription
tokenIduint256Token ID to burn

setTokenURI

Set token URI for a specific token (admin only)

function setTokenURI(uint256 tokenId, string calldata newTokenURI)
    external
    onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
tokenIduint256Token ID to set URI for
newTokenURIstringNew URI for the token

setCurrentTokenId

Set the next token ID counter (admin only)

Use this to skip token ID 0 and start from 1, or resume from a specific ID

function setCurrentTokenId(uint256 newTokenId) external onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
newTokenIduint256The next token ID to be minted

currentTokenId

Get the current token ID counter

function currentTokenId() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The next token ID that will be minted

getMintStatus

Get current mint status for a user

View function providing complete minting information and round status

function getMintStatus(address account)
    external
    view
    override
    returns (MintStatus memory status);

Parameters

NameTypeDescription
accountaddressThe address to query mint status for

Returns

NameTypeDescription
statusMintStatusComplete mint status including allocations, current price, and round status The MintStatus contains: - priorityRemaining: NFTs remaining in priority allocation - generalRemaining: NFTs remaining in general allocation - standardPrice: Current standard price per NFT based on active round - isPriorityActive: Whether priority round is currently active - isGeneralActive: Whether general round is currently active

getWhitelistInfo

Get whitelist allocations for an account

View function for checking total allocations across both rounds

function getWhitelistInfo(address account)
    external
    view
    override
    returns (WhitelistInfo memory info);

Parameters

NameTypeDescription
accountaddressThe address to query allocations for

Returns

NameTypeDescription
infoWhitelistInfoComplete whitelist information including allocations and minted amounts The WhitelistInfo contains: - priorityAllocation: Total NFTs allocated for priority round - generalAllocation: Total NFTs allocated for general round - priorityMinted: Already minted in priority round - generalMinted: Already minted in general round

getCustodialWhitelistInfo

Get custodial whitelist allocation info for a ShareX wallet address

function getCustodialWhitelistInfo(address account)
    external
    view
    override
    returns (CustodialWhitelistInfo memory info);

getSalesConfig

Get current sales configuration (from current round)

View function for checking sales round parameters and pricing

function getSalesConfig() external view override returns (SalesConfig memory config);

Returns

NameTypeDescription
configSalesConfigComplete sales configuration including timestamps and pricing The SalesConfig contains: - priorityStartTime: Priority round start timestamp (UTC+8) - priorityEndTime: Priority round end timestamp (UTC+8) - generalStartTime: General round start timestamp (UTC+8) - generalEndTime: General round end timestamp (UTC+8) - standardPrice: Price per NFT in wei

getCurrentRoundId

Get current round ID

function getCurrentRoundId() external view override returns (uint64);

Returns

NameTypeDescription
<none>uint64roundId Current active round ID (0 = no round started)

getCurrentRoundInfo

Get current round information including supply limit and minted count

function getCurrentRoundInfo() external view override returns (RoundInfo memory info);

Returns

NameTypeDescription
infoRoundInfoRoundInfo struct with roundId, supplyLimit, mintedCount, remaining

getRoundConfig

Get configuration for a specific round

function getRoundConfig(uint64 roundId)
    external
    view
    override
    returns (SalesConfig memory config, uint256 supplyLimit, uint256 mintedCount);

Parameters

NameTypeDescription
roundIduint64Round ID to query

Returns

NameTypeDescription
configSalesConfigSales configuration for the round
supplyLimituint256Maximum NFTs for the round
mintedCountuint256NFTs already minted in the round

getWhitelistInfoForRound

Get whitelist info for a user in a specific round

function getWhitelistInfoForRound(uint64 roundId, address account)
    external
    view
    override
    returns (WhitelistInfo memory info);

Parameters

NameTypeDescription
roundIduint64Round ID to query
accountaddressUser address to query

Returns

NameTypeDescription
infoWhitelistInfoWhitelistInfo for the user in the specified round

totalSupply

Get total supply of minted PowerPass NFTs

View function for supply tracking and analytics

function totalSupply() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256totalSupply Current total supply of minted NFTs

getChannelMintedCounts

Get minted counts by channel (Web3 vs Custodial/Web2)

function getChannelMintedCounts()
    external
    view
    returns (uint256 web3Count, uint256 custodialCount);

Returns

NameTypeDescription
web3Countuint256Number of NFTs minted via Web3 public mint
custodialCountuint256Number of NFTs minted via custodial/Web2 channel

maxSupply

Get maximum supply limit for PowerPass NFTs

View function for supply cap information

function maxSupply() external pure override returns (uint256);

Returns

NameTypeDescription
<none>uint256maxSupply Maximum number of NFTs that can ever be minted

supportsInterface

function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721Upgradeable, ERC721URIStorageUpgradeable, AccessControlUpgradeable, IERC165)
    returns (bool);

tokenURI

function tokenURI(uint256 tokenId)
    public
    view
    override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
    returns (string memory);

_update

Transfers tokenId from its current owner to to, or alternatively mints (or burns) if the current owner (or to) is the zero address. Returns the owner of the tokenId before the update. The auth argument is optional. If the value passed is non 0, then this function will check that auth is either the owner of the token, or approved to operate on the token (by the owner). Emits a {Transfer} event. NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.

function _update(address to, uint256 tokenId, address auth)
    internal
    override(ERC721Upgradeable)
    returns (address);

_increaseBalance

Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that a uint256 would ever overflow from increments when these increments are bounded to uint128 values. WARNING: Increasing an account's balance using this function tends to be paired with an override of the {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership remain consistent with one another.

function _increaseBalance(address account, uint128 value) internal override(ERC721Upgradeable);

_baseURI

Base URI for tokens

function _baseURI() internal view override returns (string memory);

_validateAndUpdateAllocation

Validate and update allocation for minting

function _validateAndUpdateAllocation(
    PowerPassWhitelistInfo storage userWhitelist,
    uint256 amount,
    bool isPriorityActive
) private returns (uint256 novaEligible);

Parameters

NameTypeDescription
userWhitelistPowerPassWhitelistInfo
amountuint256Amount to mint
isPriorityActiveboolWhether priority round is active

_mintTokens

Mint tokens with gas-optimized loop and proper token URI formatting

function _mintTokens(uint256 amount) private;

Parameters

NameTypeDescription
amountuint256Amount of tokens to mint

_formatTokenURI

Format token URI properly as {tokenId}.json

function _formatTokenURI(uint256 tokenId) private pure returns (string memory);

Parameters

NameTypeDescription
tokenIduint256Token ID to format

Returns

NameTypeDescription
<none>stringFormatted token URI relative path

_toString

Convert uint256 to string (gas-optimized)

function _toString(uint256 value) private pure returns (string memory);

Parameters

NameTypeDescription
valueuint256Number to convert

Returns

NameTypeDescription
<none>stringString representation of the number

_checkRoundActive

Check if priority or general round is active for given config

function _checkRoundActive(PowerPassRoundConfig storage config)
    private
    view
    returns (bool isPriorityActive, bool isGeneralActive);

Parameters

NameTypeDescription
configPowerPassRoundConfigRound configuration to check

Returns

NameTypeDescription
isPriorityActiveboolWhether priority round is active
isGeneralActiveboolWhether general round is active

_priorityRemaining

function _priorityRemaining(PowerPassWhitelistInfo storage info)
    private
    view
    returns (uint256);

_generalRemaining

function _generalRemaining(PowerPassWhitelistInfo storage info) private view returns (uint256);

_novaDiscountRemainingRaw

function _novaDiscountRemainingRaw(PowerPassWhitelistInfo storage info)
    private
    view
    returns (uint256);

_novaDiscountRemaining

function _novaDiscountRemaining(PowerPassWhitelistInfo storage info)
    private
    view
    returns (uint256);

_calculateNovaDiscountPrice

function _calculateNovaDiscountPrice(uint256 standardPrice) private pure returns (uint256);

_calculatePriorityAllocation

Calculate priority round allocation based on MAGNA/NOVA stakes

function _calculatePriorityAllocation(uint256 magnaStaked, uint256 novaStaked)
    private
    pure
    returns (uint64 allocation);

Parameters

NameTypeDescription
magnaStakeduint256Amount of MAGNA tokens staked
novaStakeduint256Amount of NOVA tokens staked

Returns

NameTypeDescription
allocationuint64Priority round allocation (max 10 NFTs)

_calculateGeneralAllocation

Calculate general round allocation based on all stakes

function _calculateGeneralAllocation(
    uint256 essentiaStaked,
    uint256 magnaStaked,
    uint256 novaStaked
) private pure returns (uint64 allocation);

Parameters

NameTypeDescription
essentiaStakeduint256Amount of ESSENTIA tokens staked
magnaStakeduint256Amount of MAGNA tokens staked
novaStakeduint256Amount of NOVA tokens staked

Returns

NameTypeDescription
allocationuint64General round allocation (max 10 NFTs)