Summary
External report (gist) shows that lockup eligibility queries can return locks that are already withdrawn or no longer actively locked, and incentives uses those query results for epoch accounting and WithdrawRewards.
Code lives in NibiruChain/nibiru-wasm; tracked from this repo for visibility.
Severity / triage
- Priority: p3 — utility reference contract correctness
- Nibiru does not deploy or operate
lockup / incentives for funded protocol incentive programs (per support ticket #833-daniel526, 2026-07-10)
- Still worth fixing so reference code is correct if third parties copy or deploy it
Production context
From contracts/README.md:
lockup and incentives are Utility reference building blocks, not core-* production contracts
- Nibiru uses
core-* contracts where Wasm is part of production infrastructure (e.g. Treasury / Hot Wallet multisigs)
Problem
LocksByDenomBetween and LocksByDenomAndAddressBetween filter with:
env.block.height + lock.duration_blocks > unlocking_after
They do not:
- exclude
lock.funds_withdrawn == true
- use the lock's actual
end_block lifecycle state
incentives consumes these queries in execute_process_epoch and execute_withdraw_rewards, so withdrawn locks can still count toward total_locked and reward payouts.
Affected code
Proposed fix
- Exclude withdrawn locks:
!lock.funds_withdrawn
- Use actual lifecycle in eligibility checks (
end_block / NOT_UNLOCKING_BLOCK_IDENTIFIER) instead of current_height + original_duration
- Add or adapt integration regression test (gist provides
withdrawn_lock_can_still_receive_incentive_rewards)
Acceptance criteria
Out of scope
Summary
External report (gist) shows that
lockupeligibility queries can return locks that are already withdrawn or no longer actively locked, andincentivesuses those query results for epoch accounting andWithdrawRewards.Code lives in NibiruChain/nibiru-wasm; tracked from this repo for visibility.
Severity / triage
lockup/incentivesfor funded protocol incentive programs (per support ticket#833-daniel526, 2026-07-10)Production context
From contracts/README.md:
lockupandincentivesare Utility reference building blocks, notcore-*production contractscore-*contracts where Wasm is part of production infrastructure (e.g. Treasury / Hot Wallet multisigs)Problem
LocksByDenomBetweenandLocksByDenomAndAddressBetweenfilter with:They do not:
lock.funds_withdrawn == trueend_blocklifecycle stateincentivesconsumes these queries inexecute_process_epochandexecute_withdraw_rewards, so withdrawn locks can still count towardtotal_lockedand reward payouts.Affected code
Proposed fix
!lock.funds_withdrawnend_block/NOT_UNLOCKING_BLOCK_IDENTIFIER) instead ofcurrent_height + original_durationwithdrawn_lock_can_still_receive_incentive_rewards)Acceptance criteria
end_blockstateOut of scope
nibi-stargateexample contract docs (see docs(wasm): warn that nibi-stargate example is non-production and permissionless #2683)