Idle NXL in the token contracts result in diluted rewards for users in TreasuryBTC
TreasuryBTC uses totalSupply() for reward share calculations, which includes idle reward-pool tokens and unvested founder/partner tokens, drastically diluting actual NXL holders' rewards.
Description
The TreasuryBTC contract distributes monthly BTC staking rewards to NXL token holders proportionally based on their holdings. However, the depositMonthlyRewards() function uses nxlToken.totalSupply() to calculate reward shares, which includes all minted NXL tokens including the 96 million tokens sitting idle in the NXLToken contract reserved for future raffle rewards, as well as unvested founder and partner tokens.
This significantly dilutes rewards for actual NXL holders, as the reward calculation treats non-circulating tokens as if they were actively held by users.
Vulnerable Scenario:
The NXLToken contract has a total supply of 100 million NXL:
- 96 million NXL sitting in the contract for future raffle rewards.
- 3 million NXL for founder (vesting over 2 years).
- 1 million NXL for partner (vesting over 1 year).
- Alice participates in raffles and earns 10,000 NXL tokens, which she holds in her wallet.
The founder deposits 1,000 USDT as monthly BTC staking rewards via depositMonthlyRewards().
The function creates a snapshot with: totalRewards = 1,000 USDT and totalNXLSupply = 100,000,000 NXL (entire total supply).
When Alice claims her rewards, the calculation is:
userReward = (1,000 USDT * 10,000 NXL) / 100,000,000 NXL = 0.1 USDT
Alice receives only 0.1 USDT despite being the only actual NXL holder who earned tokens through participation.
If the calculation used only circulating supply (10,000 NXL), Alice would receive:
userReward = (1,000 USDT * 10,000 NXL) / 10,000 NXL = 1,000 USDT
Alice loses 99.99% of her rightful rewards because idle and unvested tokens are counted in the total supply.
Impact
Users who earn NXL tokens through raffle participation receive drastically reduced rewards due to the inclusion of non-circulating tokens in the reward calculation. This creates severe unfairness:
- Actual NXL holders receive only a tiny fraction of rewards they should earn (potentially 99%+ reduction)
- Idle tokens in the NXLToken contract dilute all user rewards despite not being distributed
- Unvested founder and partner tokens further dilute rewards even though they haven't been claimed
- The vast majority of deposited rewards become unclaimable, remaining locked in the TreasuryBTC contract
- Users have no economic incentive to hold NXL tokens if rewards are negligible
Recommendation
Modify depositMonthlyRewards() to use circulating supply instead of total supply. The circulating supply should exclude tokens held by the NXLToken contract and unvested tokens:
function depositMonthlyRewards(uint256 rewardAmount) external onlyOwner {require(rewardAmount > 0, "Amount must be > 0");require(stablecoin.transferFrom(msg.sender, address(this), rewardAmount),"Transfer failed");uint256 snapshotId = snapshotCount;// Calculate circulating supply by excluding non-circulating tokensuint256 totalSupply = nxlToken.totalSupply();uint256 contractBalance = nxlToken.balanceOf(address(nxlToken));uint256 circulatingSupply = totalSupply - contractBalance;require(circulatingSupply > 0, "No circulating supply");rewardSnapshots[snapshotId] = RewardSnapshot({timestamp: block.timestamp,totalRewards: rewardAmount,totalNXLSupply: circulatingSupply,distributed: false});snapshotCount++;emit RewardsDeposited(snapshotId, rewardAmount);}
This ensures rewards are distributed only among actual NXL holders who earned their tokens through participation, rather than being diluted by idle contract reserves.
Resolution
Nexalo: Deleted the monthly WBTC rewards for NXL holders.
Zealynx: This is a fundamental protocol change, not a fix. We recommend to follow our recommendation.

