这是indexloc提供的服务,不要输入任何密码
Skip to content

fix: distribute only INIT token #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 26, 2025
Merged

fix: distribute only INIT token #409

merged 7 commits into from
May 26, 2025

Conversation

beer-1
Copy link
Member

@beer-1 beer-1 commented May 24, 2025

Description

In the current distribution module, any token can be distributed as staking rewards. However, following the changes introduced in this PR, which allows fees to be paid with dispatchable fungible assets, we need to restrict the distribution to a specific asset.

The risk arises because anyone can create a dispatchable asset and use it to pay fees. When the distribution module later attempts to distribute that asset as staking rewards, the asset creator could design it in a way that causes the distribution action to fail—potentially leading to a chain halt.

To prevent this, we are updating the logic to restrict staking reward distributions to the INIT token only.


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title, you can find examples of the prefixes below:
  • confirmed ! in the type prefix if API or client breaking change
  • targeted the correct branch
  • provided a link to the relevant issue or specification
  • reviewed "Files changed" and left comments if necessary
  • included the necessary unit and integration tests
  • updated the relevant documentation or specification, including comments for documenting Go code
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic, API design and naming, documentation is accurate, tests and test coverage

@beer-1 beer-1 self-assigned this May 24, 2025
@beer-1 beer-1 requested a review from a team as a code owner May 24, 2025 16:08
Copy link

coderabbitai bot commented May 24, 2025

📝 Walkthrough

Walkthrough

The changes refactor how internal keepers and components are accessed in the application by moving getter methods into a dedicated file and introducing a new interface for upgrade handling. Upgrade handler registration is now delegated to a versioned package, and the distribution module is updated to interact with custom keeper interfaces and focus fee allocation on a single base denomination. The Move bank keeper is enhanced to fetch balances via Move VM view functions with pagination support and improved type consistency.

Changes

File(s) Change Summary
app/app.go, app/upgrade.go Removed TestingApp interface methods and legacy upgrade handler registration; deleted upgrade.go file.
app/getters.go Added a new file with getter methods for internal keepers and components on InitiaApp.
app/upgrades/expected_app.go Added an interface specifying required getters for upgrade handling.
app/upgrades/v1_1_1/modules.go Added a variable containing base64-encoded Move modules for upgrades.
app/upgrades/v1_1_1/upgrade.go Added a new upgrade handler that decodes and publishes Move modules on upgrade.
x/distribution/keeper/allocation.go Changed fee allocation to use only the base denomination and improved error handling.
x/distribution/keeper/common_test.go Added BaseDenom method to TestDexKeeper for testing.
x/distribution/keeper/keeper.go, x/distribution/module.go Changed BankKeeper field and constructor parameter types to use custom BankKeeper interface.
x/distribution/types/expected_keepers.go Extended DexKeeper and introduced a new BankKeeper interface with additional methods.
x/move/keeper/bank.go Refactored balance queries to use Move VM view functions with JSON, added pagination and iteration support, and updated types to sdkmath.Int.
x/move/keeper/bank_test.go Expanded balance iteration test and added a new test for paginated balance retrieval.
x/move/keeper/fungible_asset.go Added detailed comment to Balance method explaining fungible asset metadata and balance.
x/move/types/connector.go Added constants and functions to read table handles and lengths from raw Move table bytes.
x/move/types/errors.go Added new error variable ErrInvalidResponse for invalid response handling.

Sequence Diagram(s)

sequenceDiagram
    participant App as InitiaApp
    participant Upgrades as upgrades/v1_1_1
    participant MoveKeeper as MoveKeeper

    App->>Upgrades: RegisterUpgradeHandlers(app)
    Upgrades->>App: GetUpgradeKeeper()
    Upgrades->>App: GetMoveKeeper()
    Upgrades->>App: GetConfigurator()
    Upgrades->>App: GetModuleManager()
    Upgrades->MoveKeeper: Publish module bundle (decoded from base64)
    MoveKeeper-->>Upgrades: Result (success or error)
Loading

Poem

🐇
Refactored getters, neat and new,
Upgrades now know just what to do.
Fees in one coin, less confusion—
Custom keepers aid the fusion!
Move modules base64 in flight,
The code hops forward, future bright.
— A rabbit in delight!
🥕


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f50edf and e57568d.

📒 Files selected for processing (1)
  • x/move/keeper/bank.go (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run test and upload codecov
  • GitHub Check: golangci-lint
  • GitHub Check: Analyze (go)
🔇 Additional comments (8)
x/move/keeper/bank.go (8)

11-11: LGTM: Import change aligns with type migration

The import change from math to sdkmath is correct and consistent with the migration throughout the file from math.Int to sdkmath.Int.


33-83: LGTM: GetBalance refactoring looks solid

The refactoring to use Move VM view functions for balance queries is well-implemented. The method now properly:

  • Queries the primary fungible store via Move VM
  • Handles JSON response unmarshaling
  • Converts string amounts to sdkmath.Int with proper validation
  • Returns appropriate error types

The error handling and type consistency improvements are excellent.


85-140: LGTM: Iteration logic correctly handles early termination

The new IterateAccountBalances implementation properly addresses the callback early-exit concern from previous reviews. The use of labeled break BALANCE_LOOP ensures that when the callback returns stop=true, both the inner coin iteration and the outer pagination loop are terminated correctly.

The pagination logic with fetchLimit and proper handling of empty results is also well-implemented.


142-217: LGTM: Pagination implementation with minor compilation fix needed

The GetPaginatedBalances method provides a solid pagination implementation with:

  • Proper table existence checking
  • Correct handling of page requests and limits
  • Next key construction for pagination
  • Appropriate coin sorting

The logic for truncating results and checking for more results is correct.


219-290: LGTM: Balances helper method is well-structured

The balances helper method properly:

  • Executes Move VM view functions for balance retrieval
  • Handles JSON response validation and parsing
  • Filters zero amounts when requested
  • Constructs pagination tokens correctly
  • Validates metadata and amount formats

The error handling throughout is comprehensive and appropriate.


296-296: LGTM: Supply method signatures updated correctly

The migration from math.Int to sdkmath.Int in the return types is consistent with the overall type migration and maintains API compatibility.

Also applies to: 322-322


608-608: LGTM: SendCoin and MultiSend parameter types updated correctly

The parameter type changes from math.Int to sdkmath.Int and []math.Int to []sdkmath.Int are consistent with the type migration throughout the codebase.

Also applies to: 647-647


700-746: LGTM: New helper method provides necessary functionality

The GetUserStoresTableHandleWithLength method properly:

  • Retrieves table handle from module store
  • Validates user address conversion
  • Checks table entry existence
  • Extracts table handle and length from stored data
  • Provides comprehensive error handling

This method supports the pagination functionality implemented in other methods.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

github-actions bot commented May 24, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copy link

@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.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4c6fe4 and ad6b7df.

📒 Files selected for processing (11)
  • app/app.go (2 hunks)
  • app/getters.go (1 hunks)
  • app/upgrade.go (0 hunks)
  • app/upgrades/expected_app.go (1 hunks)
  • app/upgrades/v1_1_1/modules.go (1 hunks)
  • app/upgrades/v1_1_1/upgrade.go (1 hunks)
  • x/distribution/keeper/allocation.go (1 hunks)
  • x/distribution/keeper/common_test.go (1 hunks)
  • x/distribution/keeper/keeper.go (2 hunks)
  • x/distribution/module.go (1 hunks)
  • x/distribution/types/expected_keepers.go (2 hunks)
💤 Files with no reviewable changes (1)
  • app/upgrade.go
🧰 Additional context used
🧬 Code Graph Analysis (4)
x/distribution/keeper/keeper.go (1)
x/distribution/types/expected_keepers.go (2)
  • BankKeeper (40-43)
  • StakingKeeper (15-32)
x/distribution/module.go (1)
x/distribution/types/expected_keepers.go (1)
  • BankKeeper (40-43)
app/upgrades/v1_1_1/upgrade.go (2)
app/upgrades/expected_app.go (1)
  • InitiaApp (11-18)
api/initia/move/v1/types.pulsar.go (1)
  • UpgradePolicy_COMPATIBLE (5917-5917)
app/app.go (1)
app/upgrades/v1_1_1/upgrade.go (1)
  • RegisterUpgradeHandlers (19-48)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run test and upload codecov
  • GitHub Check: golangci-lint
  • GitHub Check: Analyze (go)
🔇 Additional comments (17)
app/upgrades/v1_1_1/modules.go (1)

5-12: LGTM: Well-structured module definition.

The variable structure is clean and the comments clearly identify each Move module. The approach of storing base64-encoded modules as strings is appropriate for embedding binary data.

x/distribution/keeper/common_test.go (1)

581-583: LGTM: Proper test implementation.

The BaseDenom method correctly delegates to the embedded moveKeeper, maintaining consistency with the test keeper's delegation pattern. This supports testing of the new base denomination functionality introduced in the distribution keeper.

x/distribution/module.go (1)

180-180: LGTM: Consistent interface upgrade.

The change from types.BankKeeper to customtypes.BankKeeper aligns with the custom interface extension that adds the GetBalance method. This is necessary to support the new base denomination functionality while maintaining backward compatibility.

x/distribution/keeper/keeper.go (2)

26-26: LGTM: Keeper field type update.

The change from types.BankKeeper to customtypes.BankKeeper is consistent with the interface extension that adds balance querying capabilities for the base denomination functionality.


52-52: LGTM: Constructor parameter consistency.

The NewKeeper constructor parameter type update matches the struct field change, maintaining consistency across the keeper implementation. This enables the distribution keeper to utilize the enhanced bank keeper interface.

x/distribution/keeper/allocation.go (2)

43-50: LGTM: Correctly implements base denomination restriction.

The changes successfully implement the PR objective by restricting fee collection to only the base denomination (INIT token). The logic properly:

  1. Retrieves the base denomination via the dex keeper
  2. Gets only the balance for that specific denomination
  3. Includes proper error handling for the base denomination retrieval

This prevents malicious dispatchable assets from disrupting the distribution process.


53-53:

✅ Verification successful

Verify transfer logic consistency.

The transfer now uses sdk.NewCoins(feesCollectedInt) to explicitly wrap the single base denomination coin. This is correct, but ensure that this change doesn't introduce any edge cases where the fee collector module might have a non-zero balance in other denominations after the beforeAllocateTokens swap operation.


🏁 Script executed:

#!/bin/bash
# Search for other usages of SendCoinsFromModuleToModule in distribution to verify consistency
rg -A 3 -B 3 "SendCoinsFromModuleToModule.*distribution" --type go

Length of output: 68


🏁 Script executed:

#!/bin/bash
set -eo pipefail

# 1. Search all usages of SendCoinsFromModuleToModule across the repo
rg "SendCoinsFromModuleToModule" -A3 -B3 --type go

# 2. Locate the beforeAllocateTokens function to inspect its logic
rg "beforeAllocateTokens" -n --type go

# 3. Find the declaration of feesCollectedInt to confirm its type
rg "feesCollectedInt" -n --type go

Length of output: 11451


🏁 Script executed:

#!/bin/bash
set -eo pipefail

# Display the beforeAllocateTokens function to verify swap logic
rg -A30 -B0 "func (k Keeper) beforeAllocateTokens" x/distribution/keeper/allocation.go

Length of output: 107


🏁 Script executed:

#!/bin/bash
set -eo pipefail

# Dump the beforeAllocateTokens function with surrounding context
rg -n -C50 "beforeAllocateTokens" x/distribution/keeper/allocation.go

Length of output: 3618


All fee denominations are swapped before transfer—no leftover coins

The beforeAllocateTokens method (lines 18–27) iterates over GetAllBalances and calls dexKeeper.SwapToBase for every coin, ensuring that only the base denomination remains in the fee‐collector account. Immediately after, we read the base‐denom balance and wrap it in sdk.NewCoins for SendCoinsFromModuleToModule. This guarantees no non‐base coins are ever transferred.

No changes required.

app/upgrades/v1_1_1/upgrade.go (1)

23-24: Excellent context documentation.

The comment clearly links this upgrade to the movevm PR that introduced dispatchable fungible assets, providing valuable context for why this upgrade is needed alongside the distribution changes.

x/distribution/types/expected_keepers.go (2)

37-38: Well-designed interface extension.

The addition of BaseDenom method to the DexKeeper interface is clean and necessary for the security fix. The method signature appropriately returns both the denomination string and an error for proper error handling.


40-43: Excellent use of interface embedding.

The new BankKeeper interface cleanly extends the existing distribution bank keeper interface by embedding it and adding the required GetBalance method. This maintains compatibility while providing the specific functionality needed for the base denomination restriction.

app/upgrades/expected_app.go (1)

11-18: Clean interface design for upgrade system.

The InitiaApp interface properly defines the contract for upgrade handlers, providing access to essential keepers (Account, Move, Upgrade) and module management components. The interface follows good design principles by exposing only what's needed for upgrade operations.

app/app.go (2)

58-58: Import addition looks good.

The import for the new upgrade package is correctly added to support the new upgrade handler registration approach.


251-251:

✅ Verification successful

Verify the upgrade handler architecture change.

The change from app.RegisterUpgradeHandlers(app.configurator) to upgrades_v1_1_1.RegisterUpgradeHandlers(app) represents a significant architectural shift. The new approach passes the entire app instance instead of just the configurator, which allows the upgrade handler to access multiple keepers (AccountKeeper, MoveKeeper, UpgradeKeeper) as seen in the upgrade function.

This change appears correct based on the relevant code snippets, but ensure that:

  1. The old RegisterUpgradeHandlers method has been properly removed from the InitiaApp struct
  2. All necessary getters are available in the new app/getters.go file to support the upgrade handler's requirements

🏁 Script executed:

#!/bin/bash
# Description: Verify that the old RegisterUpgradeHandlers method is removed and the new upgrade interface is properly implemented

# Test 1: Check if old RegisterUpgradeHandlers method still exists in the app
echo "=== Checking for old RegisterUpgradeHandlers method ==="
rg -A 5 "func.*RegisterUpgradeHandlers" --type go

# Test 2: Verify the upgrade interface implementation
echo "=== Checking upgrade interface usage ==="
rg -A 10 "upgrades_v1_1_1\.RegisterUpgradeHandlers" --type go

# Test 3: Check if the expected app interface is properly defined
echo "=== Checking expected app interface ==="
fd "expected_app.go" --type f --exec cat {}

Length of output: 1974


Upgrade handler architecture change verified

All checks pass:

  • The legacy RegisterUpgradeHandlers method on the app type is gone (only the free function in app/upgrades/v1_1_1/upgrade.go remains).
  • The new call upgrades_v1_1_1.RegisterUpgradeHandlers(app) is correctly invoked in app/app.go.
  • The InitiaApp interface in the upgrades package defines GetAccountKeeper, GetMoveKeeper, GetUpgradeKeeper, GetConfigurator, and GetModuleManager, satisfying all handler requirements.

No further changes required.

app/getters.go (4)

1-18: Good code organization and import structure.

The extraction of getter methods into a dedicated file improves code organization and separates concerns nicely. The import statements are well-organized and include all necessary dependencies for the getter methods.


20-78: Getter methods implementation looks correct.

All getter methods follow a consistent pattern and correctly return the corresponding fields from the InitiaApp struct. The methods provide proper access to:

  • Core components (BaseApp, AccountKeeper, StakingKeeper)
  • Specialized keepers (MoveKeeper, UpgradeKeeper, IBC-related keepers)
  • Configuration components (TxConfig, Configurator, ModuleManager)

The implementation aligns with the interface requirements mentioned in the AI summary for upgrade handling.


1-85: Flag inconsistency with PR objectives.

The code changes in both files focus on refactoring getter methods and upgrade handlers, but the PR objectives specifically mention "fix: distribute only INIT token" and preventing malicious assets from disrupting staking reward distribution.

These files don't contain any distribution logic or token restriction code. The actual distribution fixes might be in other files not included in this review, or there might be a mismatch between the PR description and the actual changes being reviewed.

Likely an incorrect or invalid review comment.


80-85:

❓ Verification inconclusive

Review CheckStateContextGetter implementation.

The CheckStateContextGetter method returns a function that calls app.GetContextForCheckTx(nil). While this follows the expected pattern, passing nil as the argument might need verification to ensure it's the intended behavior for state checking contexts.


🏁 Script executed:

#!/bin/bash
# Description: Verify the usage pattern of GetContextForCheckTx with nil argument

# Check how GetContextForCheckTx is used elsewhere in the codebase
echo "=== Checking GetContextForCheckTx usage patterns ==="
rg -A 3 -B 3 "GetContextForCheckTx" --type go

# Check if there are any tests or documentation about the nil parameter
echo "=== Checking for related tests or docs ==="
rg -A 5 -B 5 "CheckStateContextGetter\|GetContextForCheckTx.*nil" --type go

Length of output: 658


🏁 Script executed:

#!/bin/bash
# Locate the GetContextForCheckTx method declaration to inspect its parameter type
echo "=== Declaration of GetContextForCheckTx with surrounding context ==="
rg -n -C3 "func (.*InitiaApp) GetContextForCheckTx" --type go

Length of output: 210


Verify GetContextForCheckTx signature and nil parameter

Please double-check that passing nil into app.GetContextForCheckTx(nil) is the intended pattern for creating a “check state” context:

• Locate the declaration of GetContextForCheckTx on *InitiaApp and confirm its first parameter’s type allows a nil value.
• Ensure that any documentation or tests for GetContextForCheckTx cover the nil case and that it produces a valid sdk.Context for state checks.
• If nil is not officially supported, consider initializing with an explicit default or overloading the method to avoid ambiguity.

Copy link

codecov bot commented May 24, 2025

Codecov Report

Attention: Patch coverage is 50.18868% with 132 lines in your changes missing coverage. Please review.

Project coverage is 40.33%. Comparing base (5198b26) to head (e57568d).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
x/move/keeper/bank.go 59.04% 52 Missing and 25 partials ⚠️
app/getters.go 7.14% 26 Missing ⚠️
app/upgrades/v1_1_1/upgrade.go 11.53% 22 Missing and 1 partial ⚠️
x/distribution/keeper/allocation.go 70.00% 2 Missing and 1 partial ⚠️
x/move/types/connector.go 75.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #409      +/-   ##
==========================================
+ Coverage   40.15%   40.33%   +0.18%     
==========================================
  Files         295      296       +1     
  Lines       27726    27882     +156     
==========================================
+ Hits        11132    11246     +114     
- Misses      14883    14898      +15     
- Partials     1711     1738      +27     
Files with missing lines Coverage Δ
app/app.go 61.46% <100.00%> (+2.98%) ⬆️
x/distribution/keeper/keeper.go 69.53% <ø> (ø)
x/move/keeper/fungible_asset.go 48.48% <ø> (-2.03%) ⬇️
x/distribution/keeper/allocation.go 68.30% <70.00%> (+0.69%) ⬆️
x/move/types/connector.go 21.80% <75.00%> (+2.44%) ⬆️
app/upgrades/v1_1_1/upgrade.go 11.53% <11.53%> (ø)
app/getters.go 7.14% <7.14%> (ø)
x/move/keeper/bank.go 49.21% <59.04%> (+8.96%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@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.

Actionable comments posted: 6

♻️ Duplicate comments (1)
x/move/keeper/bank_test.go (1)

86-92: ⚠️ Potential issue

Same compilation issue in second test

Apply the identical correction here:

-for i := range tokenNum {
+for i := 0; i < tokenNum; i++ {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f01365 and 06ec3bb.

📒 Files selected for processing (5)
  • x/move/keeper/bank.go (6 hunks)
  • x/move/keeper/bank_test.go (2 hunks)
  • x/move/keeper/fungible_asset.go (1 hunks)
  • x/move/types/connector.go (2 hunks)
  • x/move/types/errors.go (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • x/move/types/errors.go
  • x/move/keeper/fungible_asset.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
x/move/types/connector.go (1)
x/move/types/keys.go (1)
  • AddressBytesLength (31-31)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run test and upload codecov
  • GitHub Check: golangci-lint
  • GitHub Check: Analyze (go)

Copy link

@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

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 6

♻️ Duplicate comments (1)
x/move/keeper/bank_test.go (1)

86-92: ⚠️ Potential issue

Same compilation issue in second test

Apply the identical correction here:

-for i := range tokenNum {
+for i := 0; i < tokenNum; i++ {
🛑 Comments failed to post (6)
x/move/types/connector.go (2)

257-271: 🛠️ Refactor suggestion

Bounds-check before reading length field

ReadTableLengthFromTable also assumes the raw slice is AddressBytesLength + 8 bytes long. A bad slice will panic here:

length, err := DeserializeUint64(bz[cursor : cursor+8])

Add the same defensive guard:

 func ReadTableLengthFromTable(bz []byte) (math.Int, error) {
     cursor := 0

     // read table handle address
     cursor += AddressBytesLength

+    if len(bz) < cursor+8 {
+        return math.ZeroInt(), errors.Wrap(types.ErrInvalidResponse, "table bytes too short for length")
+    }
     // read table length u64
     length, err := DeserializeUint64(bz[cursor : cursor+8])
🤖 Prompt for AI Agents
In x/move/types/connector.go around lines 257 to 271, the function
ReadTableLengthFromTable slices the input byte array without checking if it has
enough length, which can cause a panic. Add a bounds check before slicing to
ensure the input slice length is at least AddressBytesLength plus 8 bytes. If
the slice is too short, return an appropriate error instead of proceeding.

252-256: ⚠️ Potential issue

Add defensive length-check before slicing bz

ReadTableHandleFromTable slices bz[:AddressBytesLength] without first ensuring that bz is at least that long.
If a malformed or truncated byte-array is passed in, the program will panic with an out-of-range slice instead of returning an error.

 func ReadTableHandleFromTable(bz []byte) (vmtypes.AccountAddress, error) {
-    return vmtypes.NewAccountAddressFromBytes(bz[:AddressBytesLength])
+    if len(bz) < AddressBytesLength {
+        return vmtypes.AccountAddress{}, errors.Wrap(types.ErrInvalidResponse, "table bytes too short for handle")
+    }
+    return vmtypes.NewAccountAddressFromBytes(bz[:AddressBytesLength])
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

// ReadTableHandleFromTable util function to read table handle from the table raw bytes
func ReadTableHandleFromTable(bz []byte) (vmtypes.AccountAddress, error) {
    if len(bz) < AddressBytesLength {
        return vmtypes.AccountAddress{}, errors.Wrap(types.ErrInvalidResponse, "table bytes too short for handle")
    }
    return vmtypes.NewAccountAddressFromBytes(bz[:AddressBytesLength])
}
🤖 Prompt for AI Agents
In x/move/types/connector.go around lines 252 to 256, the function
ReadTableHandleFromTable slices the input byte array bz without checking its
length, which can cause a panic if bz is shorter than AddressBytesLength. Add a
defensive check at the start of the function to verify that len(bz) is at least
AddressBytesLength, and if not, return an appropriate error instead of
proceeding with the slice operation.
x/move/keeper/bank.go (3)

161-165: ⚠️ Potential issue

Undefined helper min causes compilation failure

min(pageReq.Limit, tableLength.Uint64()) will not compile – there is no min function in scope and math.Min operates on floats.

-    limit := uint64(100)
-    if pageReq != nil && pageReq.Limit > 0 {
-        limit = min(pageReq.Limit, tableLength.Uint64())
-    }
+    limit := uint64(100)
+    if pageReq != nil && pageReq.Limit > 0 {
+        limit = pageReq.Limit
+        if limit > tableLength.Uint64() {
+            limit = tableLength.Uint64()
+        }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	limit := uint64(100)
	if pageReq != nil && pageReq.Limit > 0 {
		limit = pageReq.Limit
		if limit > tableLength.Uint64() {
			limit = tableLength.Uint64()
		}
	}
🤖 Prompt for AI Agents
In x/move/keeper/bank.go around lines 161 to 165, the code uses an undefined min
function to limit the page size, causing a compilation error. Replace the call
to min with a custom inline comparison that returns the smaller of pageReq.Limit
and tableLength.Uint64(), ensuring both values are of the same uint64 type to
avoid type mismatches.

107-129: ⚠️ Potential issue

Callback early-exit does not stop outer pagination loop

IterateAccountBalances breaks only the inner for _, coin loop when the callback returns true, but the surrounding for { … } continues to fetch the next page, defeating the “halt iteration” contract.

-        for _, coin := range coins {
+        outerStop := false
+        for _, coin := range coins {-            if stop, err := cb(coin); err != nil {
+            if stop, err := cb(coin); err != nil {
                 return err
             } else if stop {
-                break
+                outerStop = true
+                break
             }
         }
+
+        if outerStop {
+            break
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const fetchLimit = 100
startAfter := "null"

for {
    coins, nextKey, err := k.balances(ctx, userAddr, startAfter, fetchLimit, true)
    if err != nil {
        return err
    } else if len(coins) == 0 {
        break
    }

    outerStop := false
    for _, coin := range coins {
        if coin.Amount.IsZero() {
            continue
        }

        if stop, err := cb(coin); err != nil {
            return err
        } else if stop {
            outerStop = true
            break
        }
    }

    if outerStop {
        break
    }

    // …presumably continue pagination, e.g.:
    startAfter = nextKey
}
🤖 Prompt for AI Agents
In x/move/keeper/bank.go around lines 107 to 129, the callback's early-exit
signal only breaks the inner coin iteration loop but does not stop the outer
pagination loop, causing unwanted continued fetching. Modify the code so that
when the callback returns true, both the inner loop and the outer pagination
loop are exited immediately to fully halt iteration as intended.

255-260: ⚠️ Potential issue

for i := range resLength is invalid – results in build error

range expects an array/slice/map/string/channel; passing an int will not compile.

-    for i := range resLength {
+    for i := 0; i < resLength; i++ {

Apply the same change to any similar loop elsewhere in this file.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	coins := make([]sdk.Coin, 0, resLength)
	for i := 0; i < resLength; i++ {
		amount, ok := sdkmath.NewIntFromString(amountArray[i])
		if !ok {
			return nil, nil, moderrors.Wrapf(types.ErrInvalidResponse, "invalid balance amount: %s", amountArray[i])
		}
🤖 Prompt for AI Agents
In x/move/keeper/bank.go around lines 255 to 260, the loop uses 'for i := range
resLength' where resLength is an int, causing a build error because range
requires a collection. Change the loop to 'for i := 0; i < resLength; i++' to
iterate correctly over the intended range. Also, search the file for similar
loops using 'range' on an int and fix them the same way.
x/move/keeper/bank_test.go (1)

53-59: ⚠️ Potential issue

Loop construction invalid – use classic for instead of range int

for i := range tokenNum { … } is illegal because range can’t iterate over an int.

-for i := range tokenNum {
+for i := 0; i < tokenNum; i++ {

Repeat the fix for the identical loop in Test_GetPaginatedBalances.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	// create 200 tokens
	tokenNum := 200
	for i := 0; i < tokenNum; i++ {
		denom := fmt.Sprintf("test%d", i)
		err = moveBankKeeper.MintCoins(ctx, twoAddr, sdk.NewCoins(sdk.NewInt64Coin(denom, int64(i))))
		require.NoError(t, err)
	}
🤖 Prompt for AI Agents
In x/move/keeper/bank_test.go around lines 53 to 59, the loop uses `for i :=
range tokenNum` which is invalid because `range` cannot iterate over an integer.
Replace this with a classic for loop: `for i := 0; i < tokenNum; i++` to
correctly iterate from 0 to tokenNum-1. Apply the same fix to the identical loop
in the Test_GetPaginatedBalances function.

Copy link

@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

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 6

♻️ Duplicate comments (1)
x/move/keeper/bank_test.go (1)

86-92: ⚠️ Potential issue

Same compilation issue in second test

Apply the identical correction here:

-for i := range tokenNum {
+for i := 0; i < tokenNum; i++ {
🛑 Comments failed to post (6)
x/move/types/connector.go (2)

257-271: 🛠️ Refactor suggestion

Bounds-check before reading length field

ReadTableLengthFromTable also assumes the raw slice is AddressBytesLength + 8 bytes long. A bad slice will panic here:

length, err := DeserializeUint64(bz[cursor : cursor+8])

Add the same defensive guard:

 func ReadTableLengthFromTable(bz []byte) (math.Int, error) {
     cursor := 0

     // read table handle address
     cursor += AddressBytesLength

+    if len(bz) < cursor+8 {
+        return math.ZeroInt(), errors.Wrap(types.ErrInvalidResponse, "table bytes too short for length")
+    }
     // read table length u64
     length, err := DeserializeUint64(bz[cursor : cursor+8])
🤖 Prompt for AI Agents
In x/move/types/connector.go around lines 257 to 271, the function
ReadTableLengthFromTable slices the input byte array without checking if it has
enough length, which can cause a panic. Add a bounds check before slicing to
ensure the input slice length is at least AddressBytesLength plus 8 bytes. If
the slice is too short, return an appropriate error instead of proceeding.

252-256: ⚠️ Potential issue

Add defensive length-check before slicing bz

ReadTableHandleFromTable slices bz[:AddressBytesLength] without first ensuring that bz is at least that long.
If a malformed or truncated byte-array is passed in, the program will panic with an out-of-range slice instead of returning an error.

 func ReadTableHandleFromTable(bz []byte) (vmtypes.AccountAddress, error) {
-    return vmtypes.NewAccountAddressFromBytes(bz[:AddressBytesLength])
+    if len(bz) < AddressBytesLength {
+        return vmtypes.AccountAddress{}, errors.Wrap(types.ErrInvalidResponse, "table bytes too short for handle")
+    }
+    return vmtypes.NewAccountAddressFromBytes(bz[:AddressBytesLength])
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

// ReadTableHandleFromTable util function to read table handle from the table raw bytes
func ReadTableHandleFromTable(bz []byte) (vmtypes.AccountAddress, error) {
    if len(bz) < AddressBytesLength {
        return vmtypes.AccountAddress{}, errors.Wrap(types.ErrInvalidResponse, "table bytes too short for handle")
    }
    return vmtypes.NewAccountAddressFromBytes(bz[:AddressBytesLength])
}
🤖 Prompt for AI Agents
In x/move/types/connector.go around lines 252 to 256, the function
ReadTableHandleFromTable slices the input byte array bz without checking its
length, which can cause a panic if bz is shorter than AddressBytesLength. Add a
defensive check at the start of the function to verify that len(bz) is at least
AddressBytesLength, and if not, return an appropriate error instead of
proceeding with the slice operation.
x/move/keeper/bank.go (3)

161-165: ⚠️ Potential issue

Undefined helper min causes compilation failure

min(pageReq.Limit, tableLength.Uint64()) will not compile – there is no min function in scope and math.Min operates on floats.

-    limit := uint64(100)
-    if pageReq != nil && pageReq.Limit > 0 {
-        limit = min(pageReq.Limit, tableLength.Uint64())
-    }
+    limit := uint64(100)
+    if pageReq != nil && pageReq.Limit > 0 {
+        limit = pageReq.Limit
+        if limit > tableLength.Uint64() {
+            limit = tableLength.Uint64()
+        }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	limit := uint64(100)
	if pageReq != nil && pageReq.Limit > 0 {
		limit = pageReq.Limit
		if limit > tableLength.Uint64() {
			limit = tableLength.Uint64()
		}
	}
🤖 Prompt for AI Agents
In x/move/keeper/bank.go around lines 161 to 165, the code uses an undefined min
function to limit the page size, causing a compilation error. Replace the call
to min with a custom inline comparison that returns the smaller of pageReq.Limit
and tableLength.Uint64(), ensuring both values are of the same uint64 type to
avoid type mismatches.

107-129: ⚠️ Potential issue

Callback early-exit does not stop outer pagination loop

IterateAccountBalances breaks only the inner for _, coin loop when the callback returns true, but the surrounding for { … } continues to fetch the next page, defeating the “halt iteration” contract.

-        for _, coin := range coins {
+        outerStop := false
+        for _, coin := range coins {-            if stop, err := cb(coin); err != nil {
+            if stop, err := cb(coin); err != nil {
                 return err
             } else if stop {
-                break
+                outerStop = true
+                break
             }
         }
+
+        if outerStop {
+            break
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const fetchLimit = 100
startAfter := "null"

for {
    coins, nextKey, err := k.balances(ctx, userAddr, startAfter, fetchLimit, true)
    if err != nil {
        return err
    } else if len(coins) == 0 {
        break
    }

    outerStop := false
    for _, coin := range coins {
        if coin.Amount.IsZero() {
            continue
        }

        if stop, err := cb(coin); err != nil {
            return err
        } else if stop {
            outerStop = true
            break
        }
    }

    if outerStop {
        break
    }

    // …presumably continue pagination, e.g.:
    startAfter = nextKey
}
🤖 Prompt for AI Agents
In x/move/keeper/bank.go around lines 107 to 129, the callback's early-exit
signal only breaks the inner coin iteration loop but does not stop the outer
pagination loop, causing unwanted continued fetching. Modify the code so that
when the callback returns true, both the inner loop and the outer pagination
loop are exited immediately to fully halt iteration as intended.

255-260: ⚠️ Potential issue

for i := range resLength is invalid – results in build error

range expects an array/slice/map/string/channel; passing an int will not compile.

-    for i := range resLength {
+    for i := 0; i < resLength; i++ {

Apply the same change to any similar loop elsewhere in this file.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	coins := make([]sdk.Coin, 0, resLength)
	for i := 0; i < resLength; i++ {
		amount, ok := sdkmath.NewIntFromString(amountArray[i])
		if !ok {
			return nil, nil, moderrors.Wrapf(types.ErrInvalidResponse, "invalid balance amount: %s", amountArray[i])
		}
🤖 Prompt for AI Agents
In x/move/keeper/bank.go around lines 255 to 260, the loop uses 'for i := range
resLength' where resLength is an int, causing a build error because range
requires a collection. Change the loop to 'for i := 0; i < resLength; i++' to
iterate correctly over the intended range. Also, search the file for similar
loops using 'range' on an int and fix them the same way.
x/move/keeper/bank_test.go (1)

53-59: ⚠️ Potential issue

Loop construction invalid – use classic for instead of range int

for i := range tokenNum { … } is illegal because range can’t iterate over an int.

-for i := range tokenNum {
+for i := 0; i < tokenNum; i++ {

Repeat the fix for the identical loop in Test_GetPaginatedBalances.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	// create 200 tokens
	tokenNum := 200
	for i := 0; i < tokenNum; i++ {
		denom := fmt.Sprintf("test%d", i)
		err = moveBankKeeper.MintCoins(ctx, twoAddr, sdk.NewCoins(sdk.NewInt64Coin(denom, int64(i))))
		require.NoError(t, err)
	}
🤖 Prompt for AI Agents
In x/move/keeper/bank_test.go around lines 53 to 59, the loop uses `for i :=
range tokenNum` which is invalid because `range` cannot iterate over an integer.
Replace this with a classic for loop: `for i := 0; i < tokenNum; i++` to
correctly iterate from 0 to tokenNum-1. Apply the same fix to the identical loop
in the Test_GetPaginatedBalances function.

Copy link
Contributor

@sh-cha sh-cha left a comment

Choose a reason for hiding this comment

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

LGTM

@beer-1 beer-1 merged commit 89e64d5 into main May 26, 2025
11 checks passed
@beer-1 beer-1 deleted the feat/distribute-base-denom branch May 26, 2025 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants