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

PowerPassStaking

Git Source

Inherits: Initializable, AccessControlUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, IERC721Receiver, IPowerPassStaking

Title: PowerPassStaking - NFT Staking with Claim Request/Approval Workflow

Author: ShareX Team

Upgradeable staking contract for PowerPass NFTs with admin-approved claim flow Key Features:

  • Users stake NFTs to accumulate rewards from powerbank device orders
  • Users request to claim rewards, which requires admin approval
  • Minimal on-chain storage: only Pending/Approved requests stored
  • Rejected/Claimed requests are deleted, tracked via events for off-chain indexing

State Variables

BPS_DENOMINATOR

uint256 public constant BPS_DENOMINATOR = 10_000

DEFAULT_REWARD_BPS

uint256 public constant DEFAULT_REWARD_BPS = 2500

OPERATOR_ROLE

bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE")

_powerPassContract

IERC721 private _powerPassContract

_paymentToken

IERC20 private _paymentToken

_rewardBps

uint96 private _rewardBps

_totalStaked

uint256 private _totalStaked

_totalPendingRewards

uint256 private _totalPendingRewards

_stakingInfo

tokenId => StakingInfo

mapping(uint256 tokenId => StakingInfoInternal info) private _stakingInfo

_userStakedTokens

user => staked tokenIds

mapping(address user => uint256[] tokenIds) private _userStakedTokens

_tokenIndex

tokenId => index in user's array

mapping(uint256 tokenId => uint256 index) private _tokenIndex

_rewardBatchCounter

Counter for reward upload batches (used in events for off-chain indexing)

uint64 private _rewardBatchCounter

_requestCounter

Request counter (never resets, ensures unique requestId)

uint256 private _requestCounter

_claimRequests

requestId => ClaimRequest (only stores Pending/Approved)

mapping(uint256 requestId => ClaimRequestInternal request) private _claimRequests

_userActiveRequests

user => active requestIds (Pending + Approved)

mapping(address user => uint256[] requestIds) private _userActiveRequests

_requestIndexInUser

requestId => index in user's active requests array

mapping(uint256 requestId => uint256 index) private _requestIndexInUser

_userClaimInfo

user => UserClaimInfo

mapping(address user => UserClaimInfoInternal info) private _userClaimInfo

_pendingRequestIds

All pending request IDs (for admin query)

uint256[] private _pendingRequestIds

_pendingRequestIndex

requestId => index + 1 in pending array (0 means not in array)

mapping(uint256 requestId => uint256 indexPlusOne) private _pendingRequestIndex

__gap

uint256[30] private __gap

Functions

validAddress

modifier validAddress(address addr) ;

initialize

function initialize(address powerPass_, address paymentToken_, address admin_)
    external
    initializer
    validAddress(powerPass_)
    validAddress(paymentToken_)
    validAddress(admin_);

stake

function stake(uint256 tokenId) external override nonReentrant whenNotPaused;

stakeBatch

function stakeBatch(uint256[] calldata tokenIds) external override nonReentrant whenNotPaused;

unstake

function unstake(uint256 tokenId) external override nonReentrant whenNotPaused;

unstakeBatch

function unstakeBatch(uint256[] calldata tokenIds)
    external
    override
    nonReentrant
    whenNotPaused;

requestClaim

function requestClaim(uint256 amount)
    external
    override
    nonReentrant
    whenNotPaused
    returns (uint256 requestId);

claimRewards

function claimRewards(uint256 requestId) external override nonReentrant whenNotPaused;

claimAllApprovedRewards

function claimAllApprovedRewards() external override nonReentrant whenNotPaused;

approveClaim

function approveClaim(uint256 requestId)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    nonReentrant;

rejectClaim

function rejectClaim(uint256 requestId)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    nonReentrant;

batchApproveClaims

function batchApproveClaims(uint256[] calldata requestIds)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    nonReentrant;

batchRejectClaims

function batchRejectClaims(uint256[] calldata requestIds)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    nonReentrant;

directClaim

function directClaim(uint256 amount) external override nonReentrant whenNotPaused;

uploadOrders

function uploadOrders(uint256[] calldata tokenIds, OrderInfo[][] calldata orders)
    external
    override
    onlyRole(OPERATOR_ROLE)
    nonReentrant;

setRewardPercentage

function setRewardPercentage(uint256 rewardBps) external override onlyRole(DEFAULT_ADMIN_ROLE);

setPaymentToken

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

withdrawExcessRewards

function withdrawExcessRewards(uint256 amount)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    nonReentrant;

emergencyWithdrawNFT

function emergencyWithdrawNFT(uint256 tokenId, address to)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    validAddress(to)
    nonReentrant;

pause

function pause() external onlyRole(DEFAULT_ADMIN_ROLE);

unpause

function unpause() external onlyRole(DEFAULT_ADMIN_ROLE);

getStakingInfo

function getStakingInfo(uint256 tokenId)
    external
    view
    override
    returns (StakingInfo memory info);

isStaked

function isStaked(uint256 tokenId) external view override returns (bool);

getStaker

function getStaker(uint256 tokenId) external view override returns (address staker);

getStakedTokenIds

function getStakedTokenIds(address user) external view override returns (uint256[] memory);

powerPassContract

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

paymentToken

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

rewardPercentage

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

totalStaked

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

getUserTotalRewards

function getUserTotalRewards(address user) external view override returns (uint256);

getClaimableAmount

function getClaimableAmount(address user) external view override returns (uint256);

getUserRewardsSummary

function getUserRewardsSummary(address user)
    external
    view
    override
    returns (UserRewardsSummary memory summary);

getUserClaimInfo

function getUserClaimInfo(address user)
    external
    view
    override
    returns (UserClaimInfo memory info);

getUserActiveRequests

function getUserActiveRequests(address user)
    external
    view
    override
    returns (ClaimRequest[] memory requests);

getClaimRequest

function getClaimRequest(uint256 requestId)
    external
    view
    override
    returns (ClaimRequest memory request);

getPendingClaimRequests

function getPendingClaimRequests()
    external
    view
    override
    returns (ClaimRequest[] memory requests);

getPendingClaimRequestCount

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

onERC721Received

function onERC721Received(address, address, uint256, bytes calldata)
    external
    pure
    override
    returns (bytes4);

_stake

function _stake(address user, uint256 tokenId) internal;

_unstake

function _unstake(address user, uint256 tokenId) internal;

_removeTokenFromUser

function _removeTokenFromUser(address user, uint256 tokenId) internal;

_approveClaim

function _approveClaim(uint256 requestId) internal;

_approveClaimInternal

function _approveClaimInternal(uint256 requestId) internal returns (uint128 amount);

_rejectClaim

function _rejectClaim(uint256 requestId) internal;

_rejectClaimInternal

function _rejectClaimInternal(uint256 requestId) internal returns (uint128 amount);

_removeRequest

function _removeRequest(uint256 requestId, address user) internal;

_removeFromPendingList

function _removeFromPendingList(uint256 requestId) internal;

_processOrdersBatch

function _processOrdersBatch(
    uint256[] calldata tokenIds,
    OrderInfo[][] calldata orders,
    uint64 batchId
) internal returns (int256 netRewardChange, uint256 totalOrders);

_processTokenOrders

function _processTokenOrders(
    uint256 tokenId,
    OrderInfo[] calldata tokenOrders,
    uint256 rewardBps,
    uint64 batchId
) internal returns (int256 tokenRewardChange, uint256 orderCount);

_getUserTotalRewards

function _getUserTotalRewards(address user) internal view returns (uint256 totalRewards);

_getClaimableAmount

function _getClaimableAmount(address user) internal view returns (uint256);

Structs

StakingInfoInternal

Packed staking info (3 storage slots)

struct StakingInfoInternal {
    address owner; // 20 bytes
    uint64 stakedAt; // 8 bytes
    bool isStaked; // 1 byte
    // 3 bytes padding
    uint128 totalRewards; // 16 bytes - slot 2 (cumulative, never resets)
    uint128 rewardsAtStake; // 16 bytes - slot 3 (snapshot when user staked)
}

ClaimRequestInternal

Packed claim request (2 storage slots)

struct ClaimRequestInternal {
    address user; // 20 bytes
    uint64 requestTime; // 8 bytes
    ClaimRequestStatus status; // 1 byte
    uint128 amount; // 16 bytes - new slot
}

UserClaimInfoInternal

Packed user claim info (2 storage slots)

struct UserClaimInfoInternal {
    uint128 totalEarned; // 16 bytes - total rewards earned (includes settled from unstaked
    // NFTs)
    uint128 claimed; // 16 bytes - total claimed amount
    uint64 pendingApproval; // 8 bytes - amount waiting for approval
    uint64 approved; // 8 bytes - amount approved but not yet claimed
}