Skip to content

fix(staker): change UintTree key type from int64 to uint64#1230

Open
junghoon-vans wants to merge 7 commits intomainfrom
worktree-fix-uinttree-uint64
Open

fix(staker): change UintTree key type from int64 to uint64#1230
junghoon-vans wants to merge 7 commits intomainfrom
worktree-fix-uinttree-uint64

Conversation

@junghoon-vans
Copy link
Copy Markdown
Member

@junghoon-vans junghoon-vans commented Apr 2, 2026

Summary

  • Change all UintTree method signatures from int64 to uint64 in both staker and gov/staker packages
  • Remove EncodeInt64/DecodeInt64 helper functions (now uses EncodeUint/DecodeUint directly)
  • Add explicit non-negative assertions at every int64 → uint64 cast site to prevent silent wrap-around

Background

UintTree stores block timestamps and other non-negative values as keys. The interface previously accepted int64 and panicked at runtime on negative input. This change enforces the constraint at the type level by using uint64, and adds defensive < 0 checks at all call sites where int64 values are cast to uint64.

Changes

contract/r/gnoswap/staker/

  • tree.gno: UintTree method signatures int64uint64
  • v1/reward_calculation_types.gno: same (local UintTree copy)
  • v1/reward_calculation_pool.gno: assertions + casts in CurrentGlobalRewardRatioAccumulation, CurrentTick, CurrentStakedLiquidity, CurrentReward, cacheReward, calculateInternalReward, modifyDeposit
  • v1/reward_calculation_tick.gno: assertions + casts in CurrentOutsideAccumulation, updateCurrentOutsideAccumulation
  • v1/reward_calculation_incentives.gno: assertions + casts in startUnclaimablePeriod, endUnclaimablePeriod, calculateUnclaimableReward
  • v1/staker.gno: assertion + cast for currentTime
  • v1/calculate_pool_position_reward.gno: assertions + casts in getExternalIncentiveIdsBy
  • v1/external_incentive.gno: assertions + casts in addIncentiveIdByCreationTime, removeIncentiveIdByCreationTime
  • v1/getter.gno: updated IterateByOffset callbacks and Get calls

contract/r/gnoswap/gov/staker/

  • tree.gno: same UintTree fix
  • v1/state.gno: assertions + casts in updateTotalDelegationHistory, updateUserDelegationHistory, getLatestTotalDelegation, getLatestUserDelegation
  • v1/staker_delegation_snapshot.gno: assertions + casts in cleanTotalDelegationHistory, cleanUserDelegationHistory
  • v1/getter.gno: assertions + casts in delegation snapshot query functions

Test plan

  • gno test -v ./contract/r/gnoswap/staker/...0 build errors
  • gno test -v ./contract/r/gnoswap/gov/staker/...0 build errors

Closes #GSW-2546

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced validation to reject negative timestamps in reward calculations and delegation tracking, preventing potential edge-case errors.
  • Refactor

    • Consolidated timestamp handling utilities into a shared package for improved consistency and maintainability across staker and governance modules.
  • Tests

    • Added test coverage for timestamp key operations and edge cases.

UintTree interface was exposing int64 as key type, but negative values
were never supported (panicked at runtime). This changes all method
signatures to uint64 to enforce the constraint at the type level.

Adds explicit non-negative assertions at all int64→uint64 cast sites
to prevent silent wrap-around from accidental negative timestamp values.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Consolidates duplicated UintTree implementations from staker and gov/staker packages into a shared uinttree package. Migrates all timestamp-keyed storage operations from int64-based APIs to uint64-keyed variants (SetByInt64, IterateByInt64, etc.) and adds runtime validation to reject negative timestamps across multiple modules.

Changes

Cohort / File(s) Summary
Shared uinttree Package
contract/p/gnoswap/uinttree/doc.gno, contract/p/gnoswap/uinttree/gnomod.toml, contract/p/gnoswap/uinttree/tree.gno, contract/p/gnoswap/uinttree/tree_test.gno
New shared package providing centralized UintTree wrapper around AVL with uint64 and int64 (via ByInt64 variants) keyed operations, encoding/decoding, iteration methods, and clone functionality.
Staker tree.gno Removal
contract/r/gnoswap/staker/tree.gno
Deleted duplicate UintTree implementation and helper functions (EncodeUint, EncodeInt64, DecodeUint, DecodeInt64).
Staker tree_compat Addition
contract/r/gnoswap/staker/tree_compat.gno, contract/r/gnoswap/staker/tree_test.gno
Added compatibility wrapper exposing shared utree.UintTree via staker package; added unit tests for SetByInt64, GetByInt64, ReverseIterateByInt64, and negative-key panic validation.
Staker Core Migration
contract/r/gnoswap/staker/pool.gno
Updated pool initialization to use SetByInt64 instead of Set for tree entries (GlobalRewardRatioAccumulation, RewardCache, StakedLiquidity).
Staker v1 Reward Calculation
contract/r/gnoswap/staker/v1/reward_calculation_pool.gno, contract/r/gnoswap/staker/v1/reward_calculation_incentives.gno, contract/r/gnoswap/staker/v1/reward_calculation_tick.gno
Added negative-timestamp validation and migrated tree operations to SetByInt64, ReverseIterateByInt64, IterateByInt64 with callback key type updated to uint64.
Staker v1 Other Core Files
contract/r/gnoswap/staker/v1/staker.gno, contract/r/gnoswap/staker/v1/external_incentive.gno, contract/r/gnoswap/staker/v1/calculate_pool_position_reward.gno
Added negative-timestamp guards and updated tree operations to use *ByInt64 variants and uint64 callback keys.
Staker v1 Getters
contract/r/gnoswap/staker/v1/getter.gno
Updated pagination and lookup to treat cache/accumulation/tick keys as uint64 instead of int64, with explicit conversions where needed.
Staker v1 Tests
contract/r/gnoswap/staker/v1/calculate_pool_position_reward_test.gno, contract/r/gnoswap/staker/v1/external_incentive_test.gno, contract/r/gnoswap/staker/v1/getter_test.gno, contract/r/gnoswap/staker/v1/reward_calculation_canonical_env_test.gno, contract/r/gnoswap/staker/v1/reward_calculation_incentives_test.gno, contract/r/gnoswap/staker/v1/reward_calculation_tick_test.gno, contract/r/gnoswap/staker/v1/reward_calculation_types_test.gno
Updated test setup and assertions to cast time keys to uint64 and callback parameter types to uint64; removed deprecated EncodeInt64 tests.
Staker v1 Types
contract/r/gnoswap/staker/v1/reward_calculation_types.gno
Migrated UintTree from wrapping *avl.Tree to embedding *utree.UintTree; updated Encode/DecodeUint to delegate to shared package; removed EncodeInt64/DecodeInt64.
Gov Staker tree.gno Removal
contract/r/gnoswap/gov/staker/tree.gno
Deleted duplicate UintTree implementation and helpers.
Gov Staker tree_compat Addition
contract/r/gnoswap/gov/staker/tree_compat.gno, contract/r/gnoswap/gov/staker/tree_test.gno
Added compatibility wrapper and unit tests for SetByInt64, GetByInt64, ReverseIterateByInt64, and negative-key panic behavior.
Gov Staker v1 Delegation & State
contract/r/gnoswap/gov/staker/v1/getter.gno, contract/r/gnoswap/gov/staker/v1/state.gno, contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno
Added negative-timestamp validation and migrated history operations to SetByInt64, ReverseIterateByInt64, IterateByInt64 with uint64 callback keys.
Gov Staker v1 Tests
contract/r/gnoswap/gov/staker/v1/state_delegation_history_test.gno, contract/r/gnoswap/gov/staker/v1/state_test.gno, contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot_cleanup_test.gno, contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot_test.gno
Updated delegation-history test setup to use uint64 keys instead of int64 for Set calls and lookups.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: converting UintTree key types from int64 to uint64, which is the primary objective of this comprehensive refactoring across multiple staker modules.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-fix-uinttree-uint64

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@junghoon-vans junghoon-vans self-assigned this Apr 2, 2026
@junghoon-vans junghoon-vans added the enhancement New feature or request label Apr 2, 2026
Same fix as staker: UintTree interface was exposing int64 as key type,
but negative values were never supported. Changes all method signatures
to uint64 and adds explicit non-negative assertions at all cast sites.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
contract/r/gnoswap/staker/v1/reward_calculation_canonical_env_test.gno (1)

112-122: ⚠️ Potential issue | 🔴 Critical

Type mismatch in Iterate callback: expects uint64 key, receives int64.

The emissionUpdates.Iterate callback at line 112 declares func(key int64, value any) bool, but after the PR changes, UintTree.Iterate now invokes callbacks with key uint64. This will cause a compilation error.

🐛 Proposed fix
-		result.emissionUpdates.Iterate(start, end, func(key int64, value any) bool {
-			heights = append(heights, key)
+		result.emissionUpdates.Iterate(uint64(start), uint64(end), func(key uint64, value any) bool {
+			heights = append(heights, int64(key))
contract/r/gnoswap/staker/v1/calculate_pool_position_reward_test.gno (1)

1519-1519: ⚠️ Potential issue | 🔴 Critical

Missing uint64 cast for HistoricalTick timestamp key.

Line 1519 uses HistoricalTick().Set(baseTime-100, int32(0)) without casting to uint64, while all other occurrences in this file were updated. This inconsistency will cause a compilation error since UintTree.Set now expects uint64.

🐛 Proposed fix
-	poolResolver.HistoricalTick().Set(baseTime-100, int32(0))
+	poolResolver.HistoricalTick().Set(uint64(baseTime-100), int32(0))
contract/r/gnoswap/staker/pool.gno (1)

187-208: ⚠️ Potential issue | 🟡 Minor

Guard currentTime before seeding the UintTrees.

NewPool now writes three uint64(currentTime) keys, but this constructor still accepts any int64. A negative value will wrap and initialize the pool with misordered timestamp state.

Suggested fix
 func NewPool(poolPath string, currentTime int64) *Pool {
+	if currentTime < 0 {
+		panic("currentTime must be non-negative")
+	}
+
 	pool := &Pool{
 		poolPath:        poolPath,
 		stakedLiquidity: NewUintTree(),
contract/r/gnoswap/staker/v1/external_incentive_test.gno (2)

1485-1495: ⚠️ Potential issue | 🟠 Major

Update this panic expectation to the new guard message.

addIncentiveIdByCreationTime now panics with "creationTime must be non-negative", so this case will fail even when the negative-input path is working correctly.

Suggested fix
-			expectedPanicMessage: "negative value not supported",
+			expectedPanicMessage: "creationTime must be non-negative",

275-277: ⚠️ Potential issue | 🔴 Critical

Fix type mismatch: UintTree requires uint64 keys.

sr.NewUintTree() exposes Get/Set(key uint64, ...) methods, but the test helper at lines 275–321 declares timestamp as int64 and passes it directly to these methods. Go does not allow implicit int64→uint64 conversion; these calls will not compile.

Wrap timestamp with uint64() at all call sites:

Required conversions
-	tree.Set(timestamp, poolIncentives)
+	tree.Set(uint64(timestamp), poolIncentives)

-	value, exists := tree.Get(timestamp)
+	value, exists := tree.Get(uint64(timestamp))

-	tree.Set(timestamp, poolTree)
+	tree.Set(uint64(timestamp), poolTree)

-	value2, _ := tree.Get(timestamp)
+	value2, _ := tree.Get(uint64(timestamp))

-	tree.Set(timestamp, poolTree2)
+	tree.Set(uint64(timestamp), poolTree2)

-	value3, _ := tree.Get(timestamp)
+	value3, _ := tree.Get(uint64(timestamp))

Also update the panic expectation at line 1495: the actual implementation panics with "creationTime must be non-negative", not "negative value not supported".

contract/r/gnoswap/staker/v1/getter_test.gno (1)

688-690: ⚠️ Potential issue | 🔴 Critical

Cast int64 timestamps to uint64 for UintTree.Set calls

Lines 688-690 and 756-758 pass int64 timestamps directly to RewardCache().Set() and GlobalRewardRatioAccumulation().Set(), but both methods require uint64 keys. The type mismatch will cause compilation to fail.

Suggested fix
-	state.pool.RewardCache().Set(state.fixedTimestamp, int64(1000))
-	state.pool.RewardCache().Set(state.fixedTimestamp+100, int64(2000))
-	state.pool.RewardCache().Set(state.fixedTimestamp+200, int64(3000))
+	state.pool.RewardCache().Set(uint64(state.fixedTimestamp), int64(1000))
+	state.pool.RewardCache().Set(uint64(state.fixedTimestamp+100), int64(2000))
+	state.pool.RewardCache().Set(uint64(state.fixedTimestamp+200), int64(3000))
@@
-	state.pool.GlobalRewardRatioAccumulation().Set(state.fixedTimestamp+100, acc1)
-	state.pool.GlobalRewardRatioAccumulation().Set(state.fixedTimestamp+200, acc2)
-	state.pool.GlobalRewardRatioAccumulation().Set(state.fixedTimestamp+300, acc3)
+	state.pool.GlobalRewardRatioAccumulation().Set(uint64(state.fixedTimestamp+100), acc1)
+	state.pool.GlobalRewardRatioAccumulation().Set(uint64(state.fixedTimestamp+200), acc2)
+	state.pool.GlobalRewardRatioAccumulation().Set(uint64(state.fixedTimestamp+300), acc3)
🧹 Nitpick comments (3)
contract/r/gnoswap/staker/v1/reward_calculation_types.gno (1)

21-50: Consider extracting EncodeUint/DecodeUint to a shared package.

The EncodeUint and DecodeUint functions are duplicated verbatim in both tree.gno and this file (as noted in context snippet 1). While Gno's package model may necessitate some duplication, consider extracting these utilities to a shared p/ package to reduce maintenance burden and ensure consistent behavior.

contract/r/gnoswap/staker/v1/getter.gno (2)

466-470: Consider documenting the uint64int64 narrowing conversion.

The callback receives key uint64 but converts to int64 for the return type. While this is safe for realistic timestamp values (which fit comfortably in int64), this reverse conversion (from the new uint64 key type back to int64) is the only such narrowing in this file. If the return type []int64 is intentional for API stability, a brief comment explaining why would help future maintainers.


572-574: Misleading parameter name: tick should be timestamp.

The parameter tick uint64 is actually a timestamp/key used to look up a historical tick value, not a tick itself. The function retrieves int32 tick values stored at timestamp keys. This inconsistency with other similar functions (e.g., GetPoolRewardCache(poolPath string, timestamp uint64) on line 476) could confuse callers.

🔧 Suggested fix for parameter naming
 // GetPoolHistoricalTick returns the historical tick at a specific timestamp for a pool.
-func (s *stakerV1) GetPoolHistoricalTick(poolPath string, tick uint64) int32 {
+func (s *stakerV1) GetPoolHistoricalTick(poolPath string, timestamp uint64) int32 {
 	pool := s.getPoolByPoolPath(poolPath)
-	value, ok := pool.HistoricalTick().Get(tick)
+	value, ok := pool.HistoricalTick().Get(timestamp)
 	if !ok {
 		return 0
 	}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3fada9db-700f-448d-9087-79de2f645c65

📥 Commits

Reviewing files that changed from the base of the PR and between ebaa512 and b7f0f65.

📒 Files selected for processing (17)
  • contract/r/gnoswap/staker/pool.gno
  • contract/r/gnoswap/staker/tree.gno
  • contract/r/gnoswap/staker/v1/calculate_pool_position_reward.gno
  • contract/r/gnoswap/staker/v1/calculate_pool_position_reward_test.gno
  • contract/r/gnoswap/staker/v1/external_incentive.gno
  • contract/r/gnoswap/staker/v1/external_incentive_test.gno
  • contract/r/gnoswap/staker/v1/getter.gno
  • contract/r/gnoswap/staker/v1/getter_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_canonical_env_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_incentives.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_incentives_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_pool.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_tick.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_tick_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_types.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_types_test.gno
  • contract/r/gnoswap/staker/v1/staker.gno

Update remaining test files to use uint64 casts when passing int64
timestamps to UintTree methods.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
contract/r/gnoswap/gov/staker/v1/getter.gno (1)

146-154: ⚠️ Potential issue | 🟡 Minor

Validate snapshotTime before the empty-history fast paths.

Right now the new panic only happens when history already exists. GetTotalDelegationAmountAtSnapshot(-1) and GetUserDelegationAmountAtSnapshot(..., -1) both return (0, false) on empty/missing history, so invalid-input behavior depends on stored state. Move the check to the top of each function, and add one regression test for the empty-history case.

💡 Suggested change
 func (gs *govStakerV1) GetTotalDelegationAmountAtSnapshot(snapshotTime int64) (int64, bool) {
+	if snapshotTime < 0 {
+		panic("snapshotTime must be non-negative")
+	}
 	history := gs.store.GetTotalDelegationHistory()
 	if history.Size() == 0 {
 		return 0, false
 	}
-
-	if snapshotTime < 0 {
-		panic("snapshotTime must be non-negative")
-	}

Apply the same move in GetUserDelegationAmountAtSnapshot.

Also applies to: 192-208

contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno (1)

97-124: ⚠️ Potential issue | 🟡 Minor

math.MaxInt64 cutoffs can overwrite the real boundary snapshot.

These helpers still build an exclusive upper bound with cutoffTimestamp+1, except for math.MaxInt64. In that sentinel case, ReverseIterate(0, uint64(toTimestamp), ...) skips an entry stored exactly at the cutoff, and the following Set(uint64(cutoffTimestamp), lastValue) replaces it with the previous value. For these timestamp-backed trees, use math.MaxUint64 as the upper bound when cutoffTimestamp == math.MaxInt64, and add a regression test for that boundary. The same upper-bound helper is worth applying in the snapshot getters too.

💡 Possible fix
-	toTimestamp := cutoffTimestamp
-	if cutoffTimestamp < math.MaxInt64 {
-		toTimestamp = safeAddInt64(toTimestamp, 1)
-	}
+	upperBound := math.MaxUint64
+	if cutoffTimestamp < math.MaxInt64 {
+		upperBound = uint64(safeAddInt64(cutoffTimestamp, 1))
+	}
 ...
-	history.ReverseIterate(0, uint64(toTimestamp), func(timestamp uint64, value any) bool {
+	history.ReverseIterate(0, upperBound, func(timestamp uint64, value any) bool {

Apply the same change in cleanUserDelegationHistory.

Also applies to: 139-171


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 04e6d5d7-80ed-4809-9aaa-424daae29afd

📥 Commits

Reviewing files that changed from the base of the PR and between b7f0f65 and caed413.

📒 Files selected for processing (8)
  • contract/r/gnoswap/gov/staker/tree.gno
  • contract/r/gnoswap/gov/staker/v1/getter.gno
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot_cleanup_test.gno
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot_test.gno
  • contract/r/gnoswap/gov/staker/v1/state.gno
  • contract/r/gnoswap/gov/staker/v1/state_delegation_history_test.gno
  • contract/r/gnoswap/gov/staker/v1/state_test.gno
✅ Files skipped from review due to trivial changes (1)
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot_test.gno

@notJoon notJoon added the DO NOT MERGE do not merge this PR label Apr 3, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
contract/r/gnoswap/gov/staker/v1/getter.gno (2)

155-166: ⚠️ Potential issue | 🟠 Major

Reconcile the ReverseIterateByInt64 end-bound contract before keeping snapshotTime + 1.

The new test in contract/r/gnoswap/gov/staker/tree_test.gno treats ReverseIterateByInt64(0, 10, ...) as including key 10. If that is the intended contract, these snapshot getters now overshoot and can return the first record at T+1 for a query at T.

💡 If the upper bound is intended to be inclusive
-	toTimestamp := snapshotTime
-	if toTimestamp < math.MaxInt64 {
-		toTimestamp = toTimestamp + 1
-	}
-
-	history.ReverseIterateByInt64(0, toTimestamp, func(key uint64, value any) bool {
+	history.ReverseIterateByInt64(0, snapshotTime, func(key uint64, value any) bool {
@@
-	toTimestamp := snapshotTime
-	if toTimestamp < math.MaxInt64 {
-		toTimestamp = toTimestamp + 1
-	}
-
-	userHistory.ReverseIterateByInt64(0, toTimestamp, func(key uint64, value any) bool {
+	userHistory.ReverseIterateByInt64(0, snapshotTime, func(key uint64, value any) bool {

Also applies to: 209-220


147-154: ⚠️ Potential issue | 🟡 Minor

Validate negative snapshotTime before the empty-history fast paths.

Right now the same invalid input panics only when history exists; if the tree is empty or the user has no history, it returns (0, false) instead. That makes the new non-negative contract state-dependent.

Also applies to: 193-208

🧹 Nitpick comments (3)
contract/r/gnoswap/staker/v1/reward_calculation_pool.gno (1)

82-84: Extract duplicate panic message to a constant.

The literal "currentTime must be non-negative" and similar messages are duplicated 6+ times across this file. Per SonarCloud analysis, extract to a package-level constant for maintainability.

♻️ Proposed refactor

Add at package level:

const errNonNegativeTime = "time value must be non-negative"

Then replace all duplicate panic messages:

 func (self *PoolResolver) CurrentGlobalRewardRatioAccumulation(currentTime int64) (time int64, acc *u256.Uint) {
 	if currentTime < 0 {
-		panic("currentTime must be non-negative")
+		panic(errNonNegativeTime)
 	}
contract/r/gnoswap/staker/tree_test.gno (1)

32-42: Good panic test, but consider testing edge cases.

The test correctly verifies that negative keys trigger the expected panic. Consider adding optional tests for boundary conditions:

  • Key 0 (minimum valid)
  • Key math.MaxInt64 (maximum valid int64 → fits in uint64)
🧪 Optional edge-case test
func TestUintTreeSetByInt64EdgeCases(t *testing.T) {
	tree := NewUintTree()
	
	// Zero is valid
	tree.SetByInt64(0, "zero")
	v, ok := tree.GetByInt64(0)
	uassert.True(t, ok)
	uassert.Equal(t, "zero", v)
	
	// Max int64 is valid
	tree.SetByInt64(math.MaxInt64, "max")
	v, ok = tree.GetByInt64(math.MaxInt64)
	uassert.True(t, ok)
	uassert.Equal(t, "max", v)
}
contract/r/gnoswap/gov/staker/tree_test.gno (1)

18-42: Add a boundary regression for adjacent keys and math.MaxInt64.

These tests cover the basic adapter flow, but the fragile edge in this migration is the signed upper bound and nearby keys (T vs T+1). A targeted case there would lock the intended end-bound semantics and catch snapshot off-by-one regressions much earlier.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fafad499-6211-4389-a1b1-6362236f55cd

📥 Commits

Reviewing files that changed from the base of the PR and between caed413 and b99b770.

📒 Files selected for processing (17)
  • contract/r/gnoswap/gov/staker/tree.gno
  • contract/r/gnoswap/gov/staker/tree_test.gno
  • contract/r/gnoswap/gov/staker/util.gno
  • contract/r/gnoswap/gov/staker/v1/getter.gno
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno
  • contract/r/gnoswap/gov/staker/v1/state.gno
  • contract/r/gnoswap/staker/pool.gno
  • contract/r/gnoswap/staker/tree.gno
  • contract/r/gnoswap/staker/tree_test.gno
  • contract/r/gnoswap/staker/util.gno
  • contract/r/gnoswap/staker/v1/calculate_pool_position_reward_test.gno
  • contract/r/gnoswap/staker/v1/external_incentive_test.gno
  • contract/r/gnoswap/staker/v1/getter_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_canonical_env_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_pool.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_tick.gno
  • contract/r/gnoswap/staker/v1/staker.gno
✅ Files skipped from review due to trivial changes (2)
  • contract/r/gnoswap/staker/v1/calculate_pool_position_reward_test.gno
  • contract/r/gnoswap/staker/v1/getter_test.gno
🚧 Files skipped from review as they are similar to previous changes (6)
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_tick.gno
  • contract/r/gnoswap/staker/v1/staker.gno
  • contract/r/gnoswap/staker/v1/external_incentive_test.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_canonical_env_test.gno
  • contract/r/gnoswap/staker/pool.gno

Route timestamped tree access through package-level int64 conversion helpers and ByInt64 UintTree methods so staker and gov/staker stop repeating raw uint64 casts at call sites.
@junghoon-vans junghoon-vans force-pushed the worktree-fix-uinttree-uint64 branch 2 times, most recently from 22f5ec8 to f8c1c82 Compare April 6, 2026 08:10
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
contract/p/gnoswap/uinttree/uinttree.gno (1)

10-118: Add doc comments for the new shared UintTree API.

This introduces a public package surface, but none of the exported helpers document their panic behavior or iterator/range semantics. A short doc pass here would make the signed→unsigned migration much safer for downstream callers.

As per coding guidelines, "Exported functions have documentation".

contract/p/gnoswap/uinttree/uinttree_test.gno (1)

7-50: Please lock down the boundary cases in this new test suite.

The migration risk is at the edges, not the happy path. I'd add explicit cases for math.MaxInt64 and for IterateByInt64/ReverseIterateByInt64 bound inclusivity so future changes can't silently reintroduce wrap-around or off-by-one behavior.

contract/r/gnoswap/staker/v1/reward_calculation_pool.gno (1)

82-84: Consider one helper for the repeated time precondition.

The same panic pattern is duplicated across the file now. A tiny helper like mustNonNegativeTime(name, value) would keep the behavior and message aligned if another call site gets added later, and it should also clear the repeated-literal lint.

Also applies to: 105-107, 120-122, 165-167, 187-189, 295-300, 460-462


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d70bf62-30b2-4d7a-8a35-2017467c184a

📥 Commits

Reviewing files that changed from the base of the PR and between b99b770 and f8c1c82.

📒 Files selected for processing (21)
  • contract/p/gnoswap/uinttree/doc.gno
  • contract/p/gnoswap/uinttree/gnomod.toml
  • contract/p/gnoswap/uinttree/uinttree.gno
  • contract/p/gnoswap/uinttree/uinttree_test.gno
  • contract/r/gnoswap/gov/staker/tree.gno
  • contract/r/gnoswap/gov/staker/tree_compat.gno
  • contract/r/gnoswap/gov/staker/tree_test.gno
  • contract/r/gnoswap/gov/staker/v1/getter.gno
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno
  • contract/r/gnoswap/gov/staker/v1/state.gno
  • contract/r/gnoswap/staker/pool.gno
  • contract/r/gnoswap/staker/tree.gno
  • contract/r/gnoswap/staker/tree_compat.gno
  • contract/r/gnoswap/staker/tree_test.gno
  • contract/r/gnoswap/staker/v1/calculate_pool_position_reward.gno
  • contract/r/gnoswap/staker/v1/external_incentive.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_incentives.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_pool.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_tick.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_types.gno
  • contract/r/gnoswap/staker/v1/staker.gno
💤 Files with no reviewable changes (2)
  • contract/r/gnoswap/staker/tree.gno
  • contract/r/gnoswap/gov/staker/tree.gno
✅ Files skipped from review due to trivial changes (6)
  • contract/p/gnoswap/uinttree/doc.gno
  • contract/p/gnoswap/uinttree/gnomod.toml
  • contract/r/gnoswap/gov/staker/v1/staker_delegation_snapshot.gno
  • contract/r/gnoswap/staker/pool.gno
  • contract/r/gnoswap/gov/staker/tree_test.gno
  • contract/r/gnoswap/staker/tree_test.gno
🚧 Files skipped from review as they are similar to previous changes (6)
  • contract/r/gnoswap/staker/v1/staker.gno
  • contract/r/gnoswap/staker/v1/calculate_pool_position_reward.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_tick.gno
  • contract/r/gnoswap/gov/staker/v1/getter.gno
  • contract/r/gnoswap/staker/v1/external_incentive.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_types.gno

@junghoon-vans junghoon-vans force-pushed the worktree-fix-uinttree-uint64 branch from f8c1c82 to e3c7b1b Compare April 6, 2026 08:46
Move the duplicated realm UintTree wrappers into p/gnoswap/uinttree so staker and gov/staker share one implementation while keeping realm-local compatibility helpers.
@junghoon-vans junghoon-vans force-pushed the worktree-fix-uinttree-uint64 branch from e3c7b1b to 806e64e Compare April 6, 2026 08:48
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
contract/p/gnoswap/uinttree/tree.gno (1)

10-118: [MEDIUM] Rule: Document the exported uinttree API.

This new shared package exposes constructors, iterators, conversion helpers, and Clone without any contract docs. Consumers need the negative-int64 panic behavior, the iterator callback stop convention, and the fact that Lines 90-91 only copy value references spelled out before this becomes the canonical tree implementation.

As per coding guidelines, Exported functions have documentation.

contract/p/gnoswap/uinttree/tree_test.gno (1)

20-33: Strengthen the reverse-iterate coverage.

Lines 26-28 stop on the first callback, so this only proves the first returned element is "ten". It still passes if later in-range entries are skipped or the lower bound is mishandled.

Proposed test shape
 func TestUintTreeReverseIterateByInt64(t *testing.T) {
 	tree := NewUintTree()
+	tree.SetByInt64(0, "zero")
 	tree.SetByInt64(5, "five")
 	tree.SetByInt64(10, "ten")
+	tree.SetByInt64(11, "eleven")
 
-	var latest string
+	var visited []string
 	tree.ReverseIterateByInt64(0, 10, func(_ uint64, value any) bool {
-		latest = value.(string)
-		return true
+		visited = append(visited, value.(string))
+		return false
 	})
 
-	if latest != "ten" {
-		t.Fatalf("expected ten, got %s", latest)
+	if len(visited) != 3 || visited[0] != "ten" || visited[1] != "five" || visited[2] != "zero" {
+		t.Fatalf("unexpected reverse order: %v", visited)
 	}
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d934924d-779f-4c5b-bd8b-98b09da9f11d

📥 Commits

Reviewing files that changed from the base of the PR and between f8c1c82 and 806e64e.

📒 Files selected for processing (8)
  • contract/p/gnoswap/uinttree/doc.gno
  • contract/p/gnoswap/uinttree/gnomod.toml
  • contract/p/gnoswap/uinttree/tree.gno
  • contract/p/gnoswap/uinttree/tree_test.gno
  • contract/r/gnoswap/gov/staker/tree_compat.gno
  • contract/r/gnoswap/staker/tree.gno
  • contract/r/gnoswap/staker/tree_compat.gno
  • contract/r/gnoswap/staker/v1/reward_calculation_types.gno
💤 Files with no reviewable changes (1)
  • contract/r/gnoswap/staker/tree.gno
✅ Files skipped from review due to trivial changes (4)
  • contract/p/gnoswap/uinttree/gnomod.toml
  • contract/p/gnoswap/uinttree/doc.gno
  • contract/r/gnoswap/gov/staker/tree_compat.gno
  • contract/r/gnoswap/staker/tree_compat.gno

Switch the remaining timestamp-keyed tests to ByInt64 and drop non-negative checks that only protected old uint64 conversions, so tree-boundary validation stays centralized.
Remove the remaining alias, compatibility, and wrapper helpers so staker and gov/staker call the shared uinttree package directly for construction and key encoding.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 6, 2026

Copy link
Copy Markdown
Member

@jinoosss jinoosss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to discuss the direction of uinttree.
Since the range of keys actually used is int64, we need to determine whether it would be better to use the uint64 range.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO NOT MERGE do not merge this PR enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants