Skip to content

fix: apply changes from external audit - #42

Merged
0xstepit merged 39 commits into
mainfrom
stepit/halborn-audit
Oct 13, 2025
Merged

fix: apply changes from external audit#42
0xstepit merged 39 commits into
mainfrom
stepit/halborn-audit

Conversation

@0xstepit

@0xstepit 0xstepit commented Sep 24, 2025

Copy link
Copy Markdown
Contributor

This PR applies changes to fix findings reported by Halborn audit.

Summary by CodeRabbit

  • New Features

    • Pagination added to dispatcher and forwarder queries; query responses include pagination metadata.
    • CI vulnerability scan can run with authenticated secrets.
    • New end-to-end and test helpers for IBC escrow queries.
  • Bug Fixes

    • Prevented dispatched-count overflow.
    • Stronger ID and input validation; duplicate-action detection.
    • Enforced limits for fee recipients and max target counterparties.
  • Refactor

    • Unified error handling to gRPC status codes; several APIs now return errors/pagination.
  • Breaking Changes

    • Top-level Query/Msg services removed from protos; multiple public method signatures changed.
  • Chores

    • Broad dependency and tooling updates.

Closes ENG-522

@0xstepit 0xstepit self-assigned this Sep 24, 2025
@0xstepit 0xstepit added bug Something isn't working improvement New feature or request labels Sep 24, 2025
@coderabbitai

coderabbitai Bot commented Sep 24, 2025

Copy link
Copy Markdown

Walkthrough

Adds pagination to dispatcher and forwarder query surfaces and generated APIs; tightens protocol/action/counterparty ID parsing and validation; converts many error paths to gRPC/status or errorsmod; several keeper/controller methods now return errors; CI Nancy scan accepts secrets; some proto service declarations removed; tests and e2e helpers updated.

Changes

Cohort / File(s) Summary
CI Nancy workflow
.github/workflows/vuln_nancy.yaml, Makefile
Reorganized Nancy scan job and propagated secrets: added NANCY_USER/NANCY_TOKEN env vars and forward them into the sleuth/docker invocation as --username/--token.
Module & tooling deps
go.mod, simapp/go.mod, e2e/go.mod, tool/go.mod
Added/updated dependencies (including hyperlane-cosmos), bumped many indirect/tooling modules, and added/changed replace directives (notably remapping cosmossdk.io/collections → noble-assets fork).
Protobuf: add pagination
proto/.../dispatcher/v1/query.proto, proto/.../forwarder/v1/query.proto
Added cosmos.base.query.v1beta1 import and PageRequest/PageResponse fields to relevant request/response messages.
Protobuf: remove services / codec
proto/noble/orbiter/v1/query.proto, proto/noble/orbiter/v1/tx.proto, types/codec.go
Deleted top-level Query and Msg service declarations and removed msgservice.RegisterMsgServiceDesc call.
Generated API updates
api/.../dispatcher/v1/query.pulsar.go, api/.../forwarder/v1/query.pulsar.go
Wired new pagination fields/getters into generated messages; updated reflection, (de)serialization and imports to include v1beta1.
Dispatcher: pagination, errors, stats
keeper/component/dispatcher/* (pagination.go, query_server.go, state.go, dispatcher.go, stats.go, tests)
Added collection-pagination helper; paginated keeper APIs and query responses; replaced manual iteration with query.CollectionPaginate; query server uses NewProtocolIDFromString + gRPC status codes; added overflow guard and switched to sdkmath.Int; tests adapted.
Forwarder: pagination + validation
keeper/component/forwarder/* (state.go, query_server.go, forwarder.go, tests)
Replaced map-based paused-cross-chains API with GetPaginatedPausedCrossChains (slice + PageResponse); moved per-counterparty validation inline, enforced max counterparties, and standardized error returns; tests adapted.
Executor: action ID parsing & errors
keeper/component/executor/*
Switched to core.NewActionIDFromString parsing and standardized error wrapping via errorsmod/gRPC status; tests updated for new error messages.
Adapter keeper: GetParams now returns error
keeper/component/adapter/*
GetParams signature changed to return (Params, error); callers updated to handle/log/propagate errors; adapter query server returns gRPC Internal on failure; tests adjusted.
Controller wiring & DI
keeper/keeper.go, depinject.go
SetForwardingControllers, SetActionControllers, SetAdapterControllers now return error; depinject updated to check returned errors and panic on failure.
Fee action constants & validation
types/controller/action/fee.go, controller/action/fee.go, tests
Introduced actiontypes.BPSNormalizer and MaxFeeRecipients; fee validation enforces max recipients; controller code/tests reference new constants.
IBC adapter & e2e tests/util
controller/adapter/ibc_test.go, e2e/ibc_to_cctp_test.go, e2e/utils_queries.go
Added test cases for incomplete CCTP attributes and invalid forwarding; split failing tests into subtests; added escrow invariants and new helper GetIBCTotalEscrow.
Keeper API reshapes
keeper/*
Multiple keeper APIs changed to return pagination and/or errors; manual key iteration replaced by CollectionPaginate; query responses include Pagination fields.
Types: IDs, constants, helpers
types/core/*, types/controller/*, types/component/*
Added NewActionIDFromString, NewProtocolIDFromString, MaxCounterpartyIDLength, MaxTargetCounterparties; moved/added local constants (e.g., CCTP, CounterpartyID); added DispatchCountEntry.IsPositive() and fee-related constants & validations; tests updated.
Proto/generation removals
proto/noble/orbiter/v1/query.proto, proto/noble/orbiter/v1/tx.proto
Removed top-level Query and Msg service contents (service declarations deleted).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Q as Dispatcher QueryServer
  participant K as Dispatcher Keeper
  participant S as Store (Collections)

  Client->>Q: QueryDispatchedAmountsByProtocolID(req{protocol_id,pagination})
  Q->>Q: core.NewProtocolIDFromString(req.ProtocolId)
  alt invalid protocol_id
    Q-->>Client: gRPC InvalidArgument
  else valid
    Q->>K: GetDispatchedAmountsBySourceProtocolID(ctx,pid,pageReq)
    K->>S: query.CollectionPaginate(pairPrefix(pid), pageReq)
    S-->>K: entries, pageRes
    K-->>Q: entries, pageRes
    Q-->>Client: response{amounts, pagination}
  end
Loading
sequenceDiagram
  autonumber
  actor Client
  participant QF as Forwarder QueryServer
  participant F as Forwarder Keeper
  participant S as Store (Collections)

  Client->>QF: QueryPausedCrossChains(req{protocol_id,pagination})
  QF->>QF: core.NewProtocolIDFromString(req.ProtocolId)
  alt invalid protocol_id
    QF-->>Client: gRPC InvalidArgument
  else valid
    QF->>F: GetPaginatedPausedCrossChains(ctx,pid,pageReq)
    F->>S: query.CollectionPaginate(pairPrefix(pid), pageReq)
    S-->>F: counterpartyIDs, pageRes
    F-->>QF: ids, pageRes
    QF-->>Client: response{counterparty_ids, pagination}
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • MalteHerrmann

Poem

hop-hop, I paged the garden bright 🐇
counts now scroll, no dupes in sight
IDs parse clean beneath moonlight code
forwarders pause and pages unfold
Nancy sniffs the bytes and dreams in white ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely indicates that this PR implements fixes derived from an external audit, accurately summarizing the primary intent of applying Halborn security recommendations. It is brief, clear, and follows conventional commit style, avoiding unnecessary detail. A teammate scanning the history can immediately understand that the changes address audit findings.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch stepit/halborn-audit

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.

@0xstepit
0xstepit force-pushed the stepit/halborn-audit branch 3 times, most recently from 8cf02f9 to 433509d Compare September 24, 2025 14:54

@MalteHerrmann MalteHerrmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

great work so far! I agree with your suggestions for WONTFIXs in the Notion doc so this looks good for me -- did leave some nits here and there 🙌

Comment thread types/core/orbiter_test.go Outdated
Comment thread types/core/orbiter_test.go Outdated
Comment thread types/core/orbiter.go Outdated
Comment thread keeper/component/dispatcher/query_server.go
Comment thread keeper/component/dispatcher/state.go
Comment thread types/core/keys.go Outdated
Comment thread keeper/component/executor/query_server.go Outdated
Comment thread keeper/component/dispatcher/query_server.go Outdated
Comment thread keeper/component/dispatcher/query_server.go Outdated
Comment thread keeper/component/dispatcher/query_server.go Outdated
@0xstepit
0xstepit force-pushed the stepit/halborn-audit branch 2 times, most recently from c2182cb to cc08e8c Compare September 25, 2025 10:04
@0xstepit
0xstepit force-pushed the stepit/halborn-audit branch from cc08e8c to b1f02bf Compare September 25, 2025 11:16
@0xstepit

Copy link
Copy Markdown
Contributor Author

Thanks for the amazing review @MalteHerrmann. I did some other changes to the code for reduce repetition, have symmetric responses between forwarder and executor, and improve query responses.

@0xstepit
0xstepit marked this pull request as ready for review October 9, 2025 15:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (5)
keeper/component/dispatcher/genesis_test.go (1)

73-135: Consider adding ID format validation tests.

While the current test coverage is adequate, consider adding test cases that validate counterparty ID format requirements (e.g., IBC channels must use "channel-" prefix, handling of empty/malformed IDs). This would strengthen the test suite and document expected ID formats.

types/core/orbiter_test.go (1)

175-255: Good test coverage for Payload validation.

The new test function comprehensively covers validation scenarios including nil payloads, repeated actions, invalid IDs, missing forwarding, and successful cases. The test structure follows the coding guidelines correctly (testCases pattern, naming conventions, error assertions with require.ErrorContains).

Consider making the "error - invalid ID" test case (lines 198-206) more specific. Currently it creates both an Action with Id = 0 (unsupported) and a Forwarding with ProtocolId = 0 (unsupported), making it ambiguous which validation path triggers the error. While the test is valid as-is, you could improve precision by testing invalid Action IDs and invalid Forwarding ProtocolIds separately:

 {
-    name: "error - invalid ID",
+    name: "error - invalid action ID",
     payload: &core.Payload{
         PreActions: []*core.Action{
             {},
         },
-        Forwarding: &core.Forwarding{},
+        Forwarding: &core.Forwarding{
+            ProtocolId: core.PROTOCOL_IBC,
+            Attributes: &codectypes.Any{},
+        },
     },
     expError: "ID is not supported",
 },
+{
+    name: "error - invalid forwarding protocol ID",
+    payload: &core.Payload{
+        PreActions: []*core.Action{},
+        Forwarding: &core.Forwarding{},
+    },
+    expError: "ID is not supported",
+},
controller/adapter/ibc_test.go (1)

153-195: Consider validating parsed attribute values.

The test case correctly validates that parsing succeeds with incomplete CCTP attributes (addressing the audit finding). However, it only checks the TypeUrl and doesn't verify that the mint_recipient field was actually parsed into the CCTPAttributes.

Consider adding an assertion to verify the parsed content for more thorough validation:

require.NoError(t, err, "expected no error parsing the payload")
if tc.expectIsOrbiter {
	require.NotNil(t, payload.Forwarding)
	require.Equal(t, tc.expectPayload.Forwarding.ProtocolId, payload.Forwarding.ProtocolId, "expected different id")
	require.Equal(t, tc.expectPayload.Forwarding.Attributes.TypeUrl, payload.Forwarding.Attributes.TypeUrl, "expected different forwarding attributes type url")
	
	// Optionally verify the parsed CCTPAttributes
	var attrs forwardingtypes.CCTPAttributes
	err = encCfg.Codec.Unmarshal(payload.Forwarding.Attributes.Value, &attrs)
	require.NoError(t, err)
	require.NotEmpty(t, attrs.MintRecipient, "expected mint_recipient to be parsed")
keeper/component/adapter/adapter.go (1)

216-222: LGTM with suggestion to clarify comment.

The error handling implements a safe fallback strategy where GetParams failure results in maxSize = 0, allowing only transfers without passthrough payloads. This is a reasonable defensive approach.

Consider enhancing the comment to be more explicit:

-	// If we obtain an error, we assume 0 allowed payload size so
-	// we can execute the transfer if no payload is specified.
+	// If we obtain an error retrieving params, we use the zero-value (maxSize = 0)
+	// which only allows transfers without passthrough payloads. This safe fallback
+	// prevents processing payloads when the configuration state is uncertain.
 	params, err := a.GetParams(ctx)
 	if err != nil {
 		a.logger.Error("getting params returned an error", "err", err.Error())
 	}
keeper/component/forwarder/state_test.go (1)

42-104: Pass the subtest t into postChecks

The closures capture the outer t, so failures get reported against the parent test and risk concurrency issues if subtests ever run in parallel. Thread the subtest handle through the callback instead.

-	testCases := []struct {
+	testCases := []struct {
 		name       string
 		protocolID core.ProtocolID
 		pagination *query.PageRequest
 		expLen     int
-		postChecks func(counterparties []string, pageResp *query.PageResponse)
+		postChecks func(t *testing.T, counterparties []string, pageResp *query.PageResponse)
 	}{
@@
-			postChecks: func(counterparties []string, pageResp *query.PageResponse) {
+			postChecks: func(t *testing.T, counterparties []string, pageResp *query.PageResponse) {
@@
-			postChecks: func(counterparties []string, pageResp *query.PageResponse) {
+			postChecks: func(t *testing.T, counterparties []string, pageResp *query.PageResponse) {
@@
-			if tC.postChecks != nil {
-				tC.postChecks(counterparties, pageResp)
+			if tC.postChecks != nil {
+				tC.postChecks(t, counterparties, pageResp)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 251d01b and ffcb492.

⛔ Files ignored due to path filters (10)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • simapp/go.sum is excluded by !**/*.sum
  • tool/go.sum is excluded by !**/*.sum
  • types/component/dispatcher/query.pb.go is excluded by !**/*.pb.go
  • types/component/dispatcher/query.pb.gw.go is excluded by !**/*.pb.gw.go
  • types/component/forwarder/query.pb.go is excluded by !**/*.pb.go
  • types/component/forwarder/query.pb.gw.go is excluded by !**/*.pb.gw.go
  • types/query.pb.go is excluded by !**/*.pb.go
  • types/tx.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (53)
  • .github/workflows/vuln_nancy.yaml (1 hunks)
  • Makefile (1 hunks)
  • api/component/dispatcher/v1/query.pulsar.go (53 hunks)
  • api/component/forwarder/v1/query.pulsar.go (29 hunks)
  • controller/action/fee.go (1 hunks)
  • controller/action/fee_test.go (3 hunks)
  • controller/adapter/ibc_test.go (4 hunks)
  • depinject.go (3 hunks)
  • e2e/go.mod (11 hunks)
  • e2e/ibc_to_cctp_test.go (4 hunks)
  • e2e/utils_queries.go (2 hunks)
  • go.mod (1 hunks)
  • keeper/component/adapter/adapter.go (1 hunks)
  • keeper/component/adapter/genesis.go (1 hunks)
  • keeper/component/adapter/genesis_test.go (2 hunks)
  • keeper/component/adapter/query_server.go (2 hunks)
  • keeper/component/adapter/state.go (1 hunks)
  • keeper/component/dispatcher/dispatcher.go (0 hunks)
  • keeper/component/dispatcher/genesis_test.go (2 hunks)
  • keeper/component/dispatcher/pagination.go (1 hunks)
  • keeper/component/dispatcher/query_server.go (7 hunks)
  • keeper/component/dispatcher/state.go (3 hunks)
  • keeper/component/dispatcher/state_test.go (8 hunks)
  • keeper/component/dispatcher/stats.go (4 hunks)
  • keeper/component/dispatcher/stats_test.go (9 hunks)
  • keeper/component/executor/msg_server.go (3 hunks)
  • keeper/component/executor/msg_server_test.go (2 hunks)
  • keeper/component/executor/query_server.go (3 hunks)
  • keeper/component/forwarder/forwarder.go (2 hunks)
  • keeper/component/forwarder/genesis_test.go (1 hunks)
  • keeper/component/forwarder/msg_server.go (6 hunks)
  • keeper/component/forwarder/query_server.go (5 hunks)
  • keeper/component/forwarder/state.go (2 hunks)
  • keeper/component/forwarder/state_test.go (1 hunks)
  • keeper/keeper.go (1 hunks)
  • proto/noble/orbiter/component/dispatcher/v1/query.proto (3 hunks)
  • proto/noble/orbiter/component/forwarder/v1/query.proto (2 hunks)
  • proto/noble/orbiter/v1/query.proto (0 hunks)
  • proto/noble/orbiter/v1/tx.proto (0 hunks)
  • simapp/go.mod (2 hunks)
  • tool/go.mod (8 hunks)
  • types/codec.go (0 hunks)
  • types/component/dispatcher/dispatcher.go (1 hunks)
  • types/component/forwarder/genesis_test.go (1 hunks)
  • types/controller/action/fee.go (3 hunks)
  • types/controller/action/fee_test.go (2 hunks)
  • types/controller/forwarding/cctp.go (2 hunks)
  • types/controller/forwarding/internal.go (1 hunks)
  • types/core/id.go (4 hunks)
  • types/core/id_test.go (3 hunks)
  • types/core/keys.go (1 hunks)
  • types/core/orbiter.go (2 hunks)
  • types/core/orbiter_test.go (2 hunks)
💤 Files with no reviewable changes (4)
  • types/codec.go
  • proto/noble/orbiter/v1/query.proto
  • keeper/component/dispatcher/dispatcher.go
  • proto/noble/orbiter/v1/tx.proto
🧰 Additional context used
📓 Path-based instructions (3)
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Write unit tests using the testCases pattern
Name each test case as "success - " for success cases and "error - " for error cases; omit the prefix when no error is tested
For error-checking cases, include an expError string field in the test case and assert with require.ErrorContains(t, tC.expError, err)

Files:

  • controller/action/fee_test.go
  • keeper/component/forwarder/genesis_test.go
  • types/controller/action/fee_test.go
  • keeper/component/adapter/genesis_test.go
  • keeper/component/dispatcher/genesis_test.go
  • types/core/id_test.go
  • controller/adapter/ibc_test.go
  • types/core/orbiter_test.go
  • keeper/component/executor/msg_server_test.go
  • keeper/component/dispatcher/stats_test.go
  • e2e/ibc_to_cctp_test.go
  • types/component/forwarder/genesis_test.go
  • keeper/component/dispatcher/state_test.go
  • keeper/component/forwarder/state_test.go
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • controller/action/fee_test.go
  • keeper/component/forwarder/genesis_test.go
  • types/component/dispatcher/dispatcher.go
  • types/controller/action/fee.go
  • keeper/component/forwarder/msg_server.go
  • types/controller/action/fee_test.go
  • keeper/keeper.go
  • keeper/component/adapter/state.go
  • keeper/component/adapter/genesis_test.go
  • keeper/component/dispatcher/genesis_test.go
  • keeper/component/adapter/genesis.go
  • types/core/id_test.go
  • controller/adapter/ibc_test.go
  • keeper/component/dispatcher/stats.go
  • types/core/orbiter_test.go
  • types/core/keys.go
  • keeper/component/adapter/query_server.go
  • keeper/component/dispatcher/state.go
  • keeper/component/forwarder/query_server.go
  • types/core/orbiter.go
  • keeper/component/executor/msg_server_test.go
  • keeper/component/forwarder/forwarder.go
  • types/controller/forwarding/cctp.go
  • types/core/id.go
  • keeper/component/dispatcher/query_server.go
  • controller/action/fee.go
  • keeper/component/executor/query_server.go
  • e2e/utils_queries.go
  • keeper/component/forwarder/state.go
  • keeper/component/dispatcher/stats_test.go
  • keeper/component/dispatcher/pagination.go
  • api/component/dispatcher/v1/query.pulsar.go
  • depinject.go
  • e2e/ibc_to_cctp_test.go
  • keeper/component/adapter/adapter.go
  • types/controller/forwarding/internal.go
  • types/component/forwarder/genesis_test.go
  • keeper/component/executor/msg_server.go
  • keeper/component/dispatcher/state_test.go
  • keeper/component/forwarder/state_test.go
  • api/component/forwarder/v1/query.pulsar.go
proto/**/*.proto

📄 CodeRabbit inference engine (CLAUDE.md)

Protobuf files must be formatted and linted with buf

Files:

  • proto/noble/orbiter/component/forwarder/v1/query.proto
  • proto/noble/orbiter/component/dispatcher/v1/query.proto
🧠 Learnings (5)
📚 Learning: 2025-08-25T10:35:00.822Z
Learnt from: CR
PR: noble-assets/orbiter#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-25T10:35:00.822Z
Learning: Applies to **/*_test.go : Write unit tests using the testCases pattern

Applied to files:

  • controller/adapter/ibc_test.go
📚 Learning: 2025-07-22T12:31:35.398Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#1
File: types/interfaces/adapter.go:32-34
Timestamp: 2025-07-22T12:31:35.398Z
Learning: In the PayloadAdapter interface, the ParsePayload method returns (bool, *types.Payload, error) where the boolean indicates whether the payload is targeting the orbiter system, not success/failure. This allows distinguishing between "payload not for orbiter" (false, nil, nil) versus "payload for orbiter but parsing failed" (true/false, nil/payload, error).

Applied to files:

  • controller/adapter/ibc_test.go
📚 Learning: 2025-08-14T15:11:47.828Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#10
File: keeper/component/dispatcher/dispatcher.go:151-155
Timestamp: 2025-08-14T15:11:47.828Z
Learning: In the Orbiter codebase, the payload.Validate() method already handles nil pointer checks internally, so wrapper functions like ValidatePayload() don't need to add additional nil checks before calling payload.Validate().

Applied to files:

  • types/core/orbiter_test.go
  • types/core/orbiter.go
📚 Learning: 2025-08-18T07:30:08.537Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#15
File: keeper/component/forwarder/msg_server.go:94-102
Timestamp: 2025-08-18T07:30:08.537Z
Learning: In the orbiter codebase, when looking up protocol IDs in core.ProtocolID_value map, the default/zero value represents an unsupported protocol ID that is correctly handled by downstream validation logic, so explicit validation before the lookup is not necessary.

Applied to files:

  • types/core/id.go
📚 Learning: 2025-08-18T07:30:12.691Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#15
File: keeper/component/forwarder/msg_server.go:112-120
Timestamp: 2025-08-18T07:30:12.691Z
Learning: The user prefers defensive validation when converting string protocol IDs to typed core.ProtocolID values in the orbiter forwarder msg_server.go. They want to check if the protocol_id exists in the ProtocolID_value map before using it, rather than assuming it's valid.

Applied to files:

  • keeper/component/dispatcher/query_server.go
🧬 Code graph analysis (31)
controller/action/fee_test.go (1)
types/controller/action/fee.go (1)
  • BPSNormalizer (35-35)
keeper/component/forwarder/genesis_test.go (1)
types/core/id.pb.go (2)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_HYPERLANE (75-75)
types/component/dispatcher/dispatcher.go (2)
api/component/dispatcher/v1/dispatcher.pulsar.go (3)
  • DispatchCountEntry (1846-1854)
  • DispatchCountEntry (1869-1869)
  • DispatchCountEntry (1872-1874)
types/component/dispatcher/dispatcher.pb.go (3)
  • DispatchCountEntry (145-149)
  • DispatchCountEntry (153-153)
  • DispatchCountEntry (154-156)
keeper/component/forwarder/msg_server.go (4)
types/core/id.go (1)
  • NewProtocolIDFromString (80-91)
types/core/errors.go (2)
  • ErrUnableToPause (33-33)
  • ErrUnableToUnpause (34-34)
types/component/forwarder/events.pb.go (6)
  • EventProtocolPaused (26-28)
  • EventProtocolPaused (32-32)
  • EventProtocolPaused (33-35)
  • EventProtocolUnpaused (70-72)
  • EventProtocolUnpaused (76-76)
  • EventProtocolUnpaused (77-79)
types/core/keys.go (1)
  • MaxTargetCounterparties (53-53)
types/controller/action/fee_test.go (3)
types/controller/action/fee.go (2)
  • BPSNormalizer (35-35)
  • MaxFeeRecipients (38-38)
testutil/codec.go (1)
  • SetSDKConfig (37-40)
types/core/errors.go (1)
  • ErrNilPointer (28-28)
keeper/keeper.go (3)
testutil/mocks/controllers.go (1)
  • ForwardingController (33-35)
types/controller.go (3)
  • ForwardingController (30-33)
  • ActionController (37-40)
  • AdapterController (44-47)
types/router/router.go (1)
  • Router (44-47)
keeper/component/adapter/state.go (3)
keeper/component/adapter/adapter.go (1)
  • Adapter (45-54)
api/component/adapter/v1/adapter.pulsar.go (3)
  • Params (434-442)
  • Params (457-457)
  • Params (460-462)
types/component/adapter/adapter.pb.go (3)
  • Params (27-31)
  • Params (35-35)
  • Params (36-38)
keeper/component/adapter/genesis_test.go (2)
types/core/errors.go (1)
  • ErrNilPointer (28-28)
testutil/mocks/adapter.go (1)
  • NewAdapterComponent (34-64)
keeper/component/dispatcher/genesis_test.go (3)
types/core/id.pb.go (2)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
api/component/dispatcher/v1/dispatcher.pulsar.go (3)
  • DispatchCountEntry (1846-1854)
  • DispatchCountEntry (1869-1869)
  • DispatchCountEntry (1872-1874)
types/component/dispatcher/dispatcher.pb.go (3)
  • DispatchCountEntry (145-149)
  • DispatchCountEntry (153-153)
  • DispatchCountEntry (154-156)
keeper/component/adapter/genesis.go (4)
api/component/adapter/v1/genesis.pulsar.go (3)
  • GenesisState (465-471)
  • GenesisState (486-486)
  • GenesisState (489-491)
types/component/adapter/genesis.pb.go (3)
  • GenesisState (27-29)
  • GenesisState (33-33)
  • GenesisState (34-36)
api/component/adapter/v1/adapter.pulsar.go (3)
  • Params (434-442)
  • Params (457-457)
  • Params (460-462)
types/component/adapter/adapter.pb.go (3)
  • Params (27-31)
  • Params (35-35)
  • Params (36-38)
types/core/id_test.go (2)
types/core/id.pb.go (4)
  • ProtocolID (64-64)
  • ProtocolID (100-102)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_IBC (71-71)
types/core/id.go (2)
  • MaxCounterpartyIDLength (34-34)
  • ValidateCounterpartyID (152-183)
controller/adapter/ibc_test.go (8)
types/core/attributes.go (1)
  • ForwardingAttributes (35-41)
api/controller/forwarding/v1/cctp.pulsar.go (3)
  • CCTPAttributes (568-582)
  • CCTPAttributes (597-597)
  • CCTPAttributes (600-602)
types/controller/forwarding/cctp.pb.go (3)
  • CCTPAttributes (29-39)
  • CCTPAttributes (43-43)
  • CCTPAttributes (44-46)
testutil/payload.go (1)
  • CreateValidIBCPacketData (36-46)
types/core/keys.go (1)
  • ModuleAddress (37-37)
api/core/v1/orbiter.pulsar.go (6)
  • Payload (2188-2199)
  • Payload (2214-2214)
  • Payload (2217-2219)
  • Forwarding (2127-2143)
  • Forwarding (2158-2158)
  • Forwarding (2161-2163)
types/core/orbiter.pb.go (6)
  • Payload (128-135)
  • Payload (139-139)
  • Payload (140-142)
  • Forwarding (79-91)
  • Forwarding (95-95)
  • Forwarding (96-98)
types/core/id.pb.go (2)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_IBC (71-71)
keeper/component/dispatcher/stats.go (1)
keeper/component/dispatcher/dispatcher.go (1)
  • New (53-103)
types/core/orbiter_test.go (5)
testutil/testdata/testdata.pb.go (3)
  • TestActionAttr (75-77)
  • TestActionAttr (81-81)
  • TestActionAttr (82-84)
types/core/orbiter.go (1)
  • NewAction (41-51)
types/core/id.pb.go (2)
  • ACTION_FEE (36-36)
  • PROTOCOL_IBC (71-71)
api/core/v1/orbiter.pulsar.go (9)
  • Payload (2188-2199)
  • Payload (2214-2214)
  • Payload (2217-2219)
  • Action (2078-2090)
  • Action (2105-2105)
  • Action (2108-2110)
  • Forwarding (2127-2143)
  • Forwarding (2158-2158)
  • Forwarding (2161-2163)
types/core/orbiter.pb.go (9)
  • Payload (128-135)
  • Payload (139-139)
  • Payload (140-142)
  • Action (35-43)
  • Action (47-47)
  • Action (48-50)
  • Forwarding (79-91)
  • Forwarding (95-95)
  • Forwarding (96-98)
keeper/component/dispatcher/state.go (3)
types/component/dispatcher/dispatcher.pb.go (9)
  • DispatchedAmountEntry (75-80)
  • DispatchedAmountEntry (84-84)
  • DispatchedAmountEntry (85-87)
  • AmountDispatched (33-38)
  • AmountDispatched (42-42)
  • AmountDispatched (43-45)
  • DispatchCountEntry (145-149)
  • DispatchCountEntry (153-153)
  • DispatchCountEntry (154-156)
keeper/component/dispatcher/pagination.go (1)
  • WithCollectionPaginationQuadPrefix (28-35)
keeper/component/dispatcher/dispatcher.go (1)
  • Dispatcher (41-50)
keeper/component/forwarder/query_server.go (4)
types/core/id.go (2)
  • NewProtocolIDFromString (80-91)
  • NewCrossChainID (122-137)
keeper/component/forwarder/forwarder.go (1)
  • Forwarder (47-57)
api/component/forwarder/v1/query.pulsar.go (3)
  • QueryPausedCrossChainsResponse (3811-3820)
  • QueryPausedCrossChainsResponse (3835-3835)
  • QueryPausedCrossChainsResponse (3838-3840)
types/component/forwarder/query.pb.go (3)
  • QueryPausedCrossChainsResponse (172-177)
  • QueryPausedCrossChainsResponse (181-181)
  • QueryPausedCrossChainsResponse (182-184)
keeper/component/forwarder/forwarder.go (1)
types/core/id.go (1)
  • ValidateCounterpartyID (152-183)
types/core/id.go (1)
types/core/id.pb.go (12)
  • ActionID (29-29)
  • ActionID (57-59)
  • ActionID_value (47-51)
  • ACTION_UNSUPPORTED (34-34)
  • ProtocolID (64-64)
  • ProtocolID (100-102)
  • ProtocolID_value (88-94)
  • PROTOCOL_UNSUPPORTED (69-69)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_HYPERLANE (75-75)
  • PROTOCOL_INTERNAL (77-77)
keeper/component/dispatcher/query_server.go (3)
types/core/id.go (2)
  • NewProtocolIDFromString (80-91)
  • NewCrossChainID (122-137)
api/component/dispatcher/v1/query.pulsar.go (6)
  • QueryDispatchedCountsResponse (3574-3582)
  • QueryDispatchedCountsResponse (3597-3597)
  • QueryDispatchedCountsResponse (3600-3602)
  • QueryDispatchedAmountsResponse (3738-3746)
  • QueryDispatchedAmountsResponse (3761-3761)
  • QueryDispatchedAmountsResponse (3764-3766)
types/component/dispatcher/query.pb.go (6)
  • QueryDispatchedCountsResponse (163-167)
  • QueryDispatchedCountsResponse (171-171)
  • QueryDispatchedCountsResponse (172-174)
  • QueryDispatchedAmountsResponse (358-362)
  • QueryDispatchedAmountsResponse (366-366)
  • QueryDispatchedAmountsResponse (367-369)
controller/action/fee.go (1)
types/controller/action/fee.go (1)
  • BPSNormalizer (35-35)
keeper/component/executor/query_server.go (1)
types/core/id.go (1)
  • NewActionIDFromString (43-54)
keeper/component/forwarder/state.go (2)
keeper/component/forwarder/forwarder.go (1)
  • Forwarder (47-57)
types/component.go (1)
  • Forwarder (42-48)
keeper/component/dispatcher/stats_test.go (4)
keeper/component/dispatcher/dispatcher.go (1)
  • Dispatcher (41-50)
types/core/id.pb.go (2)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
types/packet.go (2)
  • TransferAttributes (36-43)
  • NewTransferAttributes (47-69)
types/component/dispatcher/dispatcher.pb.go (3)
  • AmountDispatched (33-38)
  • AmountDispatched (42-42)
  • AmountDispatched (43-45)
api/component/dispatcher/v1/query.pulsar.go (2)
types/component/dispatcher/query.pb.go (12)
  • QueryDispatchedCountsByProtocolIDRequest (106-111)
  • QueryDispatchedCountsByProtocolIDRequest (117-117)
  • QueryDispatchedCountsByProtocolIDRequest (118-120)
  • QueryDispatchedCountsResponse (163-167)
  • QueryDispatchedCountsResponse (171-171)
  • QueryDispatchedCountsResponse (172-174)
  • QueryDispatchedAmountsByProtocolIDRequest (299-304)
  • QueryDispatchedAmountsByProtocolIDRequest (312-312)
  • QueryDispatchedAmountsByProtocolIDRequest (313-315)
  • QueryDispatchedAmountsResponse (358-362)
  • QueryDispatchedAmountsResponse (366-366)
  • QueryDispatchedAmountsResponse (367-369)
api/component/dispatcher/v1/dispatcher.pulsar.go (6)
  • DispatchCountEntry (1846-1854)
  • DispatchCountEntry (1869-1869)
  • DispatchCountEntry (1872-1874)
  • DispatchedAmountEntry (1785-1794)
  • DispatchedAmountEntry (1809-1809)
  • DispatchedAmountEntry (1812-1814)
e2e/ibc_to_cctp_test.go (4)
e2e/utils_queries.go (1)
  • GetIBCTotalEscrow (121-140)
e2e/setup.go (2)
  • IBC (59-65)
  • Suite (67-87)
e2e/utils.go (3)
  • OneE6 (42-42)
  • GetTxsResult (183-202)
  • SearchEvents (206-229)
types/core/keys.go (1)
  • ModuleAddress (37-37)
types/controller/forwarding/internal.go (3)
types/core/attributes.go (1)
  • ForwardingAttributes (35-41)
api/controller/forwarding/v1/internal.pulsar.go (3)
  • InternalAttributes (452-459)
  • InternalAttributes (474-474)
  • InternalAttributes (477-479)
types/controller/forwarding/internal.pb.go (3)
  • InternalAttributes (29-32)
  • InternalAttributes (36-36)
  • InternalAttributes (37-39)
types/component/forwarder/genesis_test.go (1)
types/core/id.pb.go (2)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
keeper/component/executor/msg_server.go (2)
types/core/id.go (1)
  • NewActionIDFromString (43-54)
types/core/errors.go (2)
  • ErrUnableToPause (33-33)
  • ErrUnableToUnpause (34-34)
keeper/component/dispatcher/state_test.go (1)
types/core/id.pb.go (3)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_HYPERLANE (75-75)
  • PROTOCOL_CCTP (73-73)
keeper/component/forwarder/state_test.go (3)
testutil/mocks/forwarder.go (1)
  • NewForwarderComponent (33-52)
keeper/component/forwarder/forwarder.go (1)
  • Forwarder (47-57)
types/component.go (1)
  • Forwarder (42-48)
api/component/forwarder/v1/query.pulsar.go (1)
types/component/forwarder/query.pb.go (6)
  • QueryPausedCrossChainsRequest (117-122)
  • QueryPausedCrossChainsRequest (126-126)
  • QueryPausedCrossChainsRequest (127-129)
  • QueryPausedCrossChainsResponse (172-177)
  • QueryPausedCrossChainsResponse (181-181)
  • QueryPausedCrossChainsResponse (182-184)
🪛 GitHub Actions: Scan Vulnerabilities
Makefile

[error] 96-96: nancy vulnerability scan detected 1 vulnerable package (github.com/mitchellh/mapstructure) CVE-2025-11065. Exit code 1 from 'make nancy'.

🪛 OSV Scanner (2.2.3)
e2e/go.mod

[HIGH] 19-19: github.com/cosmos/cosmos-sdk 0.50.13: The x/crisis package does not cause chain halt in github.com/cosmos/cosmos-sdk

(GO-2023-1821)


[HIGH] 19-19: github.com/cosmos/cosmos-sdk 0.50.13: The x/crisis package does not charge ConstantFee in github.com/cosmos/cosmos-sdk

(GO-2023-1881)


[HIGH] 19-19: github.com/cosmos/cosmos-sdk 0.50.13: Slashing evasion in github.com/cosmos/cosmos-sdk

(GO-2024-2584)


[HIGH] 19-19: github.com/cosmos/cosmos-sdk 0.50.13: Integer Overflow vulnerability in its Validator Rewards pool can cause a chain halt in github.com/cosmos/cosmos-sdk

(GO-2025-3803)


[HIGH] 19-19: github.com/cosmos/cosmos-sdk 0.50.13: Cosmos SDK's Integer Overflow vulnerability in its Validator Rewards pool can cause a chain halt

(GHSA-p22h-3m2v-cmgh)

🔇 Additional comments (68)
types/component/forwarder/genesis_test.go (1)

46-47: LGTM! Test data now uses protocol-accurate identifiers.

The updated CounterpartyId values align with actual protocol conventions: "channel-1" follows IBC's standard channel identifier format, and "2" represents a typical CCTP numeric domain identifier. This improves test realism without changing behavior.

keeper/component/dispatcher/genesis_test.go (4)

95-98: LGTM! IBC channel naming convention applied correctly.

The updated counterparty IDs correctly use the "channel-" prefix for IBC protocol identifiers, which aligns with IBC standards. The CCTP protocol appropriately uses plain numeric identifiers.


102-105: LGTM! Consistent with dispatched amounts test data.

The counterparty ID updates maintain consistency with the DispatchedAmounts entries, correctly applying protocol-specific naming conventions.


151-154: LGTM! Export test data aligns with import test.

The DispatchedAmounts test data correctly mirrors the corresponding entries in TestInitGenesis, ensuring consistent round-trip testing.


157-160: LGTM! Export test data aligns with import test.

The DispatchedCounts test data correctly mirrors the corresponding entries in TestInitGenesis, maintaining consistency for round-trip testing.

types/core/orbiter_test.go (1)

125-125: LGTM! Typo fix improves clarity.

The correction from "an non nil" to "and non nil" makes the test case name grammatically correct and aligns with the feedback from previous reviews about expressive naming.

controller/adapter/ibc_test.go (2)

24-24: LGTM!

The import changes are appropriate for the new test case requirements.

Also applies to: 34-34


207-207: LGTM!

The enhanced assertion messages improve test clarity and will make debugging failures easier.

Also applies to: 211-220

types/component/dispatcher/dispatcher.go (1)

69-71: LGTM!

The IsPositive() helper method is well-implemented and follows the same pattern as the existing AmountDispatched.IsPositive() method, improving code consistency and readability.

types/core/orbiter.go (1)

274-280: LGTM!

The duplicate action ID detection is correctly implemented. The logic uses a map to efficiently track visited IDs and reports duplicates before proceeding to per-action validation, which is the right order of operations. This addresses the validation requirement mentioned in past review comments.

types/controller/forwarding/cctp.go (2)

30-32: LGTM!

Relocating the CCTPNobleDomain constant from the core package to the forwarding package improves cohesion by keeping CCTP-specific configuration close to its usage.


62-62: LGTM!

The validation correctly references the new local CCTPNobleDomain constant, maintaining the same validation logic while using the relocated constant.

types/controller/forwarding/internal.go (2)

30-31: LGTM!

Extracting the counterparty ID into a named constant improves maintainability by eliminating the magic string and making the value's purpose explicit.


36-36: LGTM!

The method correctly returns the new CounterpartyID constant, maintaining the same behavior while improving code clarity.

types/controller/action/fee.go (3)

32-39: LGTM!

The constants are well-defined and appropriately documented:

  • BPSNormalizer (10,000) provides the basis points denominator for fee calculations
  • MaxFeeRecipients (5) sets a reasonable upper bound on the number of fee recipients

Relocating these from the core package to the action package improves cohesion by keeping fee-related configuration with fee logic.


63-69: LGTM!

The validation correctly enforces the maximum number of fee recipients using the new MaxFeeRecipients constant, preventing potential abuse or performance issues from excessive recipient lists.


85-90: LGTM!

The validation correctly uses the local BPSNormalizer constant and provides a clear error message. The logic ensures basis points are within the valid range (0 < BasisPoints ≤ 10,000).

types/core/keys.go (1)

53-53: LGTM!

The MaxTargetCounterparties constant (100) establishes a reasonable upper bound for the number of counterparty IDs that can be targeted in operations like pause/unpause, helping prevent resource exhaustion or abuse.

go.mod (1)

183-183: Verify replace directive consistency and document fork rationale
Both go.mod files replace cosmossdk.io/collections with v0.0.0-20250923134424-edd65694c2f7; confirm this fork provides required functionality beyond upstream and record its rationale in the README or CONTRIBUTING guide.

simapp/go.mod (1)

228-229: Verify necessity of fork and plan upstream contribution
Cannot automatically confirm that upstream SDK lacks “iterate raw” support. Please manually check and ensure:

  • Upstream cosmossdk.io/collections truly missing a raw-iteration API.
  • This replace is a temporary workaround; consider opening an upstream issue or PR.
  • Pseudo-version edd65694c2f7 corresponds to a stable commit in the fork.
keeper/component/forwarder/msg_server.go (2)

59-78: LGTM: Improved ID parsing and error handling.

The refactor to use core.NewProtocolIDFromString provides better validation and consistent error handling. The error messages are clear and properly wrapped.


122-127: LGTM: Essential validation added.

The validation ensuring no more than core.MaxTargetCounterparties counterparties can be paused in a single transaction prevents potential DoS vectors and excessive gas consumption.

keeper/component/dispatcher/pagination.go (1)

28-35: LGTM: Clean pagination helper.

The generic pagination helper follows the standard Cosmos SDK pattern and provides type-safe prefix filtering for Quad-key collections.

keeper/component/dispatcher/stats_test.go (2)

108-132: LGTM: Important overflow test added.

The new test case properly validates that dispatched count overflow is detected and returns an error when attempting to increment beyond math.MaxUint64. This prevents potential state corruption from integer overflow.


25-30: LGTM: Proper migration to sdkmath.

The migration from an external math package to cosmossdk.io/math (aliased as sdkmath) aligns with Cosmos SDK best practices for deterministic on-chain arithmetic and overflow protection.

Based on learnings.

Also applies to: 45-47

tool/go.mod (1)

1-221: No issues identified.

The tooling dependency updates appear routine. These are dev-only dependencies with no runtime impact.

keeper/component/executor/msg_server.go (2)

55-76: LGTM: Consistent ID parsing pattern.

The refactor to use core.NewActionIDFromString mirrors the pattern in the forwarder component, providing consistent validation and error handling across the codebase.


87-107: LGTM: Proper error handling.

The error handling correctly uses core.ErrUnableToUnpause for the unpause operation, and error messages are clear and properly wrapped.

types/core/id.go (3)

33-35: LGTM: Reasonable length constraint.

The 32-character maximum for counterparty IDs provides a sensible upper bound while accommodating standard chain/channel identifiers.


43-54: LGTM: Improved ID construction with validation.

The new NewActionIDFromString and NewProtocolIDFromString constructors provide clear error messages when IDs don't exist in the enum or aren't supported, improving debuggability over direct map lookups.

Also applies to: 80-91


152-183: LGTM: Protocol-specific validation.

The updated ValidateCounterpartyID properly enforces protocol-specific constraints:

  • IBC: validates channel ID format
  • CCTP/Hyperlane: requires numeric IDs
  • Internal: allows any format
  • Unsupported: rejects

This prevents invalid IDs from being accepted based on protocol type.

types/core/id_test.go (1)

130-190: LGTM: Comprehensive validation tests.

The new TestValidateCounterpartyID test cases cover:

  • Empty IDs
  • Length limits
  • Protocol-specific format requirements (numeric for CCTP, channel format for IBC)
  • Default/unsupported protocol handling

This provides good coverage of the validation logic.

e2e/go.mod (3)

303-303: Document and verify collections fork (e2e/go.mod:303)
No documentation exists for the cosmossdk.io/collections replace directive. Confirm the fork’s compatibility with the current Cosmos SDK version and update project documentation (e.g., README or docs/) with the rationale for using this fork.


8-8: Confirm hyperlane-cosmos version
Integration is covered in e2e tests (utils_queries.go, setup.go, ibc_to_hyperlane_test.go); ensure v1.0.1 is the intended version.


1-300: Follow up: upgrade Cosmos SDK to address critical vulnerabilities

Static analysis flagged high severity issues in cosmos-sdk v0.50.13:

  • x/crisis: GO-2023-1821, GO-2023-1881
  • Slashing evasion: GO-2024-2584
  • Validator rewards integer overflow: GO-2025-3803, GHSA-p22h-3m2v-cmgh

Track and remediate in a follow-up PR by upgrading to the latest patched v0.50.x release. Please verify the correct patched version and update accordingly.

keeper/component/executor/msg_server_test.go (1)

57-57: LGTM!

The test expectations correctly reflect the new error message format from core.NewActionIDFromString, which provides more precise error messages for invalid action IDs.

Also applies to: 133-133

keeper/component/adapter/query_server.go (1)

53-56: LGTM!

Proper error handling using gRPC status codes. The use of codes.Internal is appropriate for server-side parameter retrieval failures.

controller/action/fee.go (1)

243-243: LGTM!

The constant reference has been correctly updated to use actiontypes.BPSNormalizer, aligning with the refactoring that moves domain-specific constants to the action package.

keeper/component/forwarder/genesis_test.go (1)

105-106: LGTM!

The test data has been correctly updated to use the new cross-chain ID format with numeric counterparty identifiers, aligning with the pagination refactoring.

keeper/component/forwarder/query_server.go (2)

54-57: LGTM!

Proper input validation using core.NewProtocolIDFromString with appropriate gRPC status codes. The use of codes.InvalidArgument for validation failures is correct.

Also applies to: 96-99


130-141: LGTM!

Pagination support has been correctly integrated into the PausedCrossChains query. The response now includes both the counterparty IDs and pagination metadata, following standard Cosmos SDK query patterns.

types/controller/action/fee_test.go (2)

57-57: LGTM!

The constant reference has been correctly updated to use actiontypes.BPSNormalizer, consistent with the refactoring in other files.


100-159: LGTM!

Excellent test coverage for FeeAttributes validation. The test properly validates nil attributes, boundary cases, and the maximum recipients constraint using actiontypes.MaxFeeRecipients.

keeper/component/executor/query_server.go (4)

26-27: LGTM: gRPC status imports added.

The addition of gRPC status and codes imports aligns with the migration from cosmossdk.io/errors to standard gRPC error handling in query servers.


54-56: Good: Defensive action ID validation.

The switch from core.NewActionID(core.ActionID_value[req.ActionId]) to core.NewActionIDFromString(req.ActionId) provides defensive validation that checks both existence and support before construction. The gRPC status code InvalidArgument is appropriate for invalid input.

Based on learnings


59-62: Good: Appropriate error code for internal failures.

Using status.Error(codes.Internal, ...) for state retrieval failures correctly signals server-side issues to clients.


78-81: Good: Consistent gRPC error handling.

The PausedActions query method correctly uses codes.Internal for internal state retrieval errors, maintaining consistency with the error handling pattern in IsActionPaused.

keeper/component/adapter/genesis_test.go (2)

36-37: Good: Correct expectation for uninitialized state.

Based on the past review discussion, expecting an error from GetParams before genesis initialization is correct behavior, as the underlying state has not been populated yet.


43-44: Good: Proper error handling for GetParams.

All calls to GetParams now correctly handle the two-value return signature, with appropriate error checks where needed.

Also applies to: 59-64

proto/noble/orbiter/component/forwarder/v1/query.proto (2)

6-6: LGTM: Pagination import added.

The cosmos base query pagination import is correctly added to support the new pagination fields in the query messages.


54-55: Good: Consistent pagination support.

Pagination fields are correctly added to both the request (PageRequest) and response (PageResponse) messages for the PausedCrossChains query, following standard Cosmos SDK patterns.

Also applies to: 63-64

keeper/component/forwarder/forwarder.go (2)

138-150: Good: Inline validation improves clarity.

The inline protocol and per-counterparty validation in Pause is clearer than the previous ValidateCrossChains approach. Each counterparty ID is validated against the protocol ID using core.ValidateCounterpartyID, with appropriate error wrapping.


161-175: Good: Symmetric validation in Unpause.

The validation logic in Unpause mirrors that in Pause, ensuring consistency across pause/unpause operations.

e2e/ibc_to_cctp_test.go (4)

67-68: Good: Pre-test escrow verification.

Adding the initial escrow check before running subtests establishes a baseline for escrow invariant verification.


70-76: Good: Improved test structure with descriptive names.

The split into subtests with clear names (FailingParsingWithoutForwarding and FailingAfterParsingInvalidForwarding) makes the test intent explicit and improves maintainability.


87-175: Good: Escrow invariant checks added.

The test now properly captures initial and final escrow amounts (lines 103, 173-174) and verifies neutrality, ensuring the failing transaction doesn't leave orphaned funds.


177-274: Good: Comprehensive test for post-parsing errors.

The new test function covers the scenario where forwarding parsing succeeds but validation fails in the CCTP handler. Key assertions include:

  • Orbiter middleware error in the ACK (lines 244-249)
  • Exactly one IBC tx recorded (line 253)
  • No DepositForBurn CCTP event emitted (line 258)
  • Counterparty balance restored (lines 266-271)
  • Escrow invariant maintained (lines 272-273)
proto/noble/orbiter/component/dispatcher/v1/query.proto (2)

5-5: LGTM: Pagination import added.

The cosmos base query pagination import is correctly added to support the new pagination fields in dispatcher query messages.


69-70: Good: Comprehensive pagination support.

Pagination fields are consistently added to all by-protocol query messages (both counts and amounts), enabling efficient querying of large result sets. The pattern follows standard Cosmos SDK conventions.

Also applies to: 77-78, 100-101, 108-109

keeper/component/dispatcher/query_server.go (7)

26-27: LGTM: gRPC status imports added.

The addition of gRPC status and codes imports supports the migration from cosmossdk.io/errors to standard gRPC error handling in query servers.


53-66: Good: Defensive protocol ID validation.

Both source and destination protocol IDs use NewProtocolIDFromString for defensive validation, with contextual error messages distinguishing between source and destination failures. The cross-chain ID construction error handling is also appropriate.

Based on learnings


77-89: Good: Existence check with clear error code.

The IsPositive() check on the retrieved counts provides a clear existence test, and returning codes.NotFound with a descriptive message when no data exists is the correct gRPC pattern. Setting Pagination to nil for single-entry responses is appropriate.


100-117: Good: Paginated query implementation.

The DispatchedCountsByDestinationProtocolID query correctly:

  • Validates the protocol ID using NewProtocolIDFromString
  • Passes the pagination request to the state layer
  • Returns both counts and pagination response
  • Uses codes.Internal for state retrieval errors

128-141: Good: Symmetric implementation for source protocol queries.

The DispatchedCountsBySourceProtocolID query mirrors the destination query implementation, maintaining consistency across the API surface.


152-193: Good: Complete validation for amounts query.

The DispatchedAmounts query includes all necessary validations:

  • Empty denom check (line 152-154)
  • Source and destination protocol ID validation
  • Source and destination cross-chain ID validation
  • Existence check using IsPositive()
  • Contextual error messages

203-220: Good: Consistent pagination for amounts queries.

Both DispatchedAmountsByDestinationProtocolID and DispatchedAmountsBySourceProtocolID follow the same pagination pattern as the counts queries, providing a uniform API experience.

Also applies to: 231-248

keeper/keeper.go (2)

194-205: All callers handle SetActionControllers errors. Verified that the only invocation in depinject.go checks the returned error and panics on failure.


180-191: All callers handle SetForwardingControllers error Verified the invocation in depinject.go:141 checks the returned error.

Comment thread controller/adapter/ibc_test.go Outdated
Comment thread keeper/component/adapter/genesis.go
Comment thread keeper/component/dispatcher/state.go
Comment thread keeper/component/forwarder/msg_server.go
Comment thread keeper/component/forwarder/msg_server.go
Comment thread keeper/component/forwarder/state_test.go
Comment thread keeper/keeper.go
Comment thread Makefile

@MalteHerrmann MalteHerrmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks great @0xstepit; awesome work!! 💪

Comment thread keeper/component/forwarder/msg_server.go
Comment thread keeper/component/forwarder/msg_server.go Outdated
Comment thread keeper/component/forwarder/msg_server.go
Comment thread types/core/id.go Outdated
0xstepit and others added 2 commits October 13, 2025 15:10
Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
types/core/id.go (2)

43-54: Refine error message to avoid redundancy.

The error message at line 50 includes "action ID" prefix when err.Error() (from line 71) already contains "action ID:", resulting in redundant text like "action ID action ID: ACTION_UNSUPPORTED is not supported".

Apply this diff to improve clarity:

 	actionID, err := NewActionID(val)
 	if err != nil {
-		return ACTION_UNSUPPORTED, fmt.Errorf("action ID %s is not supported", err.Error())
+		return ACTION_UNSUPPORTED, err
 	}

Or alternatively, if you want to add context:

 	actionID, err := NewActionID(val)
 	if err != nil {
-		return ACTION_UNSUPPORTED, fmt.Errorf("action ID %s is not supported", err.Error())
+		return ACTION_UNSUPPORTED, fmt.Errorf("invalid action ID: %w", err)
 	}

80-91: Refine error message to avoid redundancy.

The error message at line 87 has the same redundancy issue as NewActionIDFromString — it includes "protocol ID" prefix when err.Error() (from line 107) already contains "protocol ID:", resulting in redundant text.

Apply this diff to improve clarity:

 	protocolID, err := NewProtocolID(val)
 	if err != nil {
-		return PROTOCOL_UNSUPPORTED, fmt.Errorf("protocol ID %s is not supported", err.Error())
+		return PROTOCOL_UNSUPPORTED, err
 	}

Or alternatively:

 	protocolID, err := NewProtocolID(val)
 	if err != nil {
-		return PROTOCOL_UNSUPPORTED, fmt.Errorf("protocol ID %s is not supported", err.Error())
+		return PROTOCOL_UNSUPPORTED, fmt.Errorf("invalid protocol ID: %w", err)
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ffcb492 and 13b0049.

📒 Files selected for processing (1)
  • types/core/id.go (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • types/core/id.go
🧠 Learnings (1)
📚 Learning: 2025-08-18T07:30:08.537Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#15
File: keeper/component/forwarder/msg_server.go:94-102
Timestamp: 2025-08-18T07:30:08.537Z
Learning: In the orbiter codebase, when looking up protocol IDs in core.ProtocolID_value map, the default/zero value represents an unsupported protocol ID that is correctly handled by downstream validation logic, so explicit validation before the lookup is not necessary.

Applied to files:

  • types/core/id.go
🧬 Code graph analysis (1)
types/core/id.go (2)
api/core/v1/id.pulsar.go (10)
  • ActionID (500-500)
  • ActionID (536-538)
  • ActionID (540-542)
  • ActionID (549-551)
  • ActionID_value (519-523)
  • ProtocolID (556-556)
  • ProtocolID (600-602)
  • ProtocolID (604-606)
  • ProtocolID (613-615)
  • ProtocolID_value (581-587)
types/core/id.pb.go (12)
  • ActionID (29-29)
  • ActionID (57-59)
  • ActionID_value (47-51)
  • ACTION_UNSUPPORTED (34-34)
  • ProtocolID (64-64)
  • ProtocolID (100-102)
  • ProtocolID_value (88-94)
  • PROTOCOL_UNSUPPORTED (69-69)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_HYPERLANE (75-75)
  • PROTOCOL_INTERNAL (77-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: prepare
🔇 Additional comments (3)
types/core/id.go (3)

30-31: LGTM!

The import of channeltypes from ibc-go v8 is correct and necessary for the IBC channel ID validation added in line 167. Based on learnings, v8.6.1 is the current stable patch release with security fixes.


33-35: LGTM!

The MaxCounterpartyIDLength constant provides a reasonable upper bound for counterparty IDs and adds defense-in-depth against unbounded string inputs.


152-191: LGTM!

The per-protocol validation logic is well-designed and addresses audit findings:

  • Max length check (lines 157-162): Prevents unbounded strings
  • Protocol-specific rules (lines 164-176):
    • PROTOCOL_IBC: Uses ibc-go's channel ID validation
    • PROTOCOL_CCTP, PROTOCOL_HYPERLANE: Requires numeric IDs
    • PROTOCOL_INTERNAL: Flexible for internal use
    • Correctly rejects unsupported protocols
  • Helper function (lines 185-191): isInteger is safe given the 32-character max length constraint

The validation correctly handles the zero/default value case for PROTOCOL_UNSUPPORTED as indicated in the learnings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
types/core/id.go (1)

185-191: Consider using ParseUint for domain ID validation.

The function correctly validates integer strings. However, for CCTP/HYPERLANE domain IDs (typically unsigned 32-bit values), strconv.ParseUint(s, 10, 32) might be more precise than strconv.Atoi.

 func isInteger(s string) bool {
-	_, err := strconv.Atoi(s)
+	_, err := strconv.ParseUint(s, 10, 32)
 
 	return err == nil
 }

This would:

  • Reject negative numbers (which are invalid for domain IDs)
  • Enforce 32-bit range explicitly (matching typical domain ID size)
  • Be more self-documenting of the expected input range
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ffcb492 and 13b0049.

📒 Files selected for processing (1)
  • types/core/id.go (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • types/core/id.go
🧠 Learnings (1)
📚 Learning: 2025-08-18T07:30:08.537Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#15
File: keeper/component/forwarder/msg_server.go:94-102
Timestamp: 2025-08-18T07:30:08.537Z
Learning: In the orbiter codebase, when looking up protocol IDs in core.ProtocolID_value map, the default/zero value represents an unsupported protocol ID that is correctly handled by downstream validation logic, so explicit validation before the lookup is not necessary.

Applied to files:

  • types/core/id.go
🧬 Code graph analysis (1)
types/core/id.go (2)
api/core/v1/id.pulsar.go (10)
  • ActionID (500-500)
  • ActionID (536-538)
  • ActionID (540-542)
  • ActionID (549-551)
  • ActionID_value (519-523)
  • ProtocolID (556-556)
  • ProtocolID (600-602)
  • ProtocolID (604-606)
  • ProtocolID (613-615)
  • ProtocolID_value (581-587)
types/core/id.pb.go (12)
  • ActionID (29-29)
  • ActionID (57-59)
  • ActionID_value (47-51)
  • ACTION_UNSUPPORTED (34-34)
  • ProtocolID (64-64)
  • ProtocolID (100-102)
  • ProtocolID_value (88-94)
  • PROTOCOL_UNSUPPORTED (69-69)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_HYPERLANE (75-75)
  • PROTOCOL_INTERNAL (77-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build
  • GitHub Check: prepare
  • GitHub Check: unit-test
  • GitHub Check: lint
🔇 Additional comments (3)
types/core/id.go (3)

30-35: LGTM! Security constraint added.

The addition of MaxCounterpartyIDLength constant and the ibc-go channeltypes import are appropriate security improvements that prevent unbounded string lengths and enable proper IBC channel ID validation.


152-183: Excellent per-protocol validation logic!

The updated validation provides protocol-specific rules:

  • IBC channels validated using official ibc-go validation
  • CCTP/HYPERLANE domain IDs validated as integers
  • Length constraint prevents DoS attacks
  • Unsupported protocols explicitly rejected

This is a strong security improvement that aligns with audit findings.


141-150: LGTM! Proper integration of per-protocol validation.

The updated call to ValidateCounterpartyID correctly passes the protocol parameter, enabling the per-protocol validation logic.

Comment thread types/core/id.go
Comment thread types/core/id.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
keeper/component/forwarder/state_test.go (1)

55-88: Fix typos in test case names.

All four case titles still say “portocol”. Please spell it “protocol” so the descriptions read cleanly.

-			name:       "success - all paused cross-chain for portocol ID 3 with no pagination",
+			name:       "success - all paused cross-chain for protocol ID 3 with no pagination",
@@
-			name:       "success - all paused cross-chain for portocol ID 3 with pagination",
+			name:       "success - all paused cross-chain for protocol ID 3 with pagination",
@@
-			name:       "success - all paused cross-chain for portocol ID 3 with pagination reversed",
+			name:       "success - all paused cross-chain for protocol ID 3 with pagination reversed",
types/core/id.go (1)

43-51: Fix %w usage—passing err.Error() breaks compilation.

fmt.Errorf with the %w verb expects an error, but err.Error() is a string. This does not compile and also loses the original error chain. Pass the error itself.

-		return ACTION_UNSUPPORTED, fmt.Errorf("action ID %s is not supported: %w", id, err.Error())
+		return ACTION_UNSUPPORTED, fmt.Errorf("action ID %s is not supported: %w", id, err)
keeper/component/dispatcher/state.go (1)

191-194: Thanks for fixing the source/destination context in the error.

Message now correctly refers to “source protocol ID.”

🧹 Nitpick comments (6)
keeper/component/dispatcher/state.go (3)

176-189: Avoid redundant store reads in paginate mappers (amounts).

Mapper re-fetches each value via Get. Use the provided v to build entries and save I/O.

Apply within these ranges:

-        func(k DispatchedAmountsKey, v dispatchertypes.AmountDispatched) (*dispatchertypes.DispatchedAmountEntry, error) {
-            entry, err := d.getDispatchedAmountEntryFromKey(ctx, k)
-            if err != nil {
-                return nil, err
-            }
-            return &entry, nil
-        },
+        func(k DispatchedAmountsKey, v dispatchertypes.AmountDispatched) (*dispatchertypes.DispatchedAmountEntry, error) {
+            entry, err := d.makeDispatchedAmountEntryFromKeyValue(k, v)
+            if err != nil {
+                return nil, err
+            }
+            return &entry, nil
+        },

Add helper (outside the ranges):

func (d *Dispatcher) makeDispatchedAmountEntryFromKeyValue(
    k DispatchedAmountsKey,
    v dispatchertypes.AmountDispatched,
) (dispatchertypes.DispatchedAmountEntry, error) {
    var entry dispatchertypes.DispatchedAmountEntry

    sourceID, err := core.NewCrossChainID(core.ProtocolID(k.K1()), k.K2())
    if err != nil {
        return entry, errorsmod.Wrap(err, "failed to create source cross-chain ID")
    }
    destID, err := core.ParseCrossChainID(k.K3())
    if err != nil {
        return entry, errorsmod.Wrap(err, "failed to parse destination cross-chain ID")
    }

    entry.SourceId = &sourceID
    entry.DestinationId = &destID
    entry.Denom = k.K4()
    entry.AmountDispatched = v
    return entry, nil
}

Also applies to: 205-218


413-425: Avoid redundant store reads in paginate mappers (counts).

Same pattern: build entries from key+value to avoid an extra Get per item.

Apply within these ranges:

-        func(k DispatchedCountsKey, v uint64) (*dispatchertypes.DispatchCountEntry, error) {
-            entry, err := d.getDispatchCountEntryFromKey(ctx, k)
-            if err != nil {
-                return nil, err
-            }
-            return &entry, nil
-        },
+        func(k DispatchedCountsKey, v uint64) (*dispatchertypes.DispatchCountEntry, error) {
+            entry, err := d.makeDispatchCountEntryFromKeyValue(k, v)
+            if err != nil {
+                return nil, err
+            }
+            return &entry, nil
+        },

Add helper (outside the ranges):

func (d *Dispatcher) makeDispatchCountEntryFromKeyValue(
    k DispatchedCountsKey,
    v uint64,
) (dispatchertypes.DispatchCountEntry, error) {
    var entry dispatchertypes.DispatchCountEntry

    sourceID, err := core.NewCrossChainID(core.ProtocolID(k.K1()), k.K2())
    if err != nil {
        return entry, errorsmod.Wrap(err, "failed to create source cross-chain ID")
    }
    destID, err := core.NewCrossChainID(core.ProtocolID(k.K3()), k.K4())
    if err != nil {
        return entry, errorsmod.Wrap(err, "failed to create destination cross-chain ID")
    }

    entry.SourceId = &sourceID
    entry.DestinationId = &destID
    entry.Count = v
    return entry, nil
}

Also applies to: 442-455


408-412: Parameter naming consistency.

Consider renaming parameter “id” to “protocolID” to match other getters.

Also applies to: 437-441

controller/adapter/ibc_test.go (3)

47-55: Use expError field name per repo’s testCases guideline.

Rename errorContains to expError and update its usage.

As per coding guidelines

         expectIsOrbiter bool
         expectPayload   *core.Payload
-        expectError     bool
-        errorContains   string
+        expectError     bool
+        expError        string

And where asserted (see Line 217 below):

-                require.ErrorContains(t, err, tc.errorContains, "expected a different error")
+                require.ErrorContains(t, err, tc.expError, "expected a different error")

57-72: Align test names; avoid "skip -" prefix.

Prefer “success - …” or omit the prefix for non-error cases to keep naming consistent across tests.

As per coding guidelines

-            name:            "skip - not ics20 packet",
+            name:            "success - not ics20 packet",
...
-            name: "skip - receiver is not orbiter module",
+            name: "success - receiver is not orbiter module",

206-219: Assertions cleanup reads well; tiny message nit (optional).

Messages improved; consider a clearer message for the isOrbiter flag.

-            require.Equal(
+            require.Equal(
                 t,
                 tc.expectIsOrbiter,
                 isOrbiterPayload,
-                "expected payload to be orbiter payload",
+                "unexpected isOrbiterPayload value",
             )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13b0049 and b5c2b68.

📒 Files selected for processing (5)
  • controller/adapter/ibc_test.go (4 hunks)
  • keeper/component/dispatcher/state.go (3 hunks)
  • keeper/component/forwarder/msg_server.go (6 hunks)
  • keeper/component/forwarder/state_test.go (1 hunks)
  • types/core/id.go (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • keeper/component/forwarder/msg_server.go
  • controller/adapter/ibc_test.go
  • keeper/component/dispatcher/state.go
  • keeper/component/forwarder/state_test.go
  • types/core/id.go
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Write unit tests using the testCases pattern
Name each test case as "success - " for success cases and "error - " for error cases; omit the prefix when no error is tested
For error-checking cases, include an expError string field in the test case and assert with require.ErrorContains(t, tC.expError, err)

Files:

  • controller/adapter/ibc_test.go
  • keeper/component/forwarder/state_test.go
🧠 Learnings (4)
📚 Learning: 2025-08-25T10:35:00.822Z
Learnt from: CR
PR: noble-assets/orbiter#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-25T10:35:00.822Z
Learning: Applies to **/*_test.go : Write unit tests using the testCases pattern

Applied to files:

  • controller/adapter/ibc_test.go
📚 Learning: 2025-07-22T12:31:35.398Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#1
File: types/interfaces/adapter.go:32-34
Timestamp: 2025-07-22T12:31:35.398Z
Learning: In the PayloadAdapter interface, the ParsePayload method returns (bool, *types.Payload, error) where the boolean indicates whether the payload is targeting the orbiter system, not success/failure. This allows distinguishing between "payload not for orbiter" (false, nil, nil) versus "payload for orbiter but parsing failed" (true/false, nil/payload, error).

Applied to files:

  • controller/adapter/ibc_test.go
📚 Learning: 2025-08-25T10:35:00.822Z
Learnt from: CR
PR: noble-assets/orbiter#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-25T10:35:00.822Z
Learning: Applies to **/*_test.go : Name each test case as "success - <DESCRIPTION>" for success cases and "error - <DESCRIPTION>" for error cases; omit the prefix when no error is tested

Applied to files:

  • keeper/component/forwarder/state_test.go
📚 Learning: 2025-08-18T07:30:08.537Z
Learnt from: 0xstepit
PR: noble-assets/orbiter#15
File: keeper/component/forwarder/msg_server.go:94-102
Timestamp: 2025-08-18T07:30:08.537Z
Learning: In the orbiter codebase, when looking up protocol IDs in core.ProtocolID_value map, the default/zero value represents an unsupported protocol ID that is correctly handled by downstream validation logic, so explicit validation before the lookup is not necessary.

Applied to files:

  • types/core/id.go
🧬 Code graph analysis (5)
keeper/component/forwarder/msg_server.go (4)
types/core/id.go (1)
  • NewProtocolIDFromString (80-95)
types/core/errors.go (2)
  • ErrUnableToPause (33-33)
  • ErrUnableToUnpause (34-34)
types/component/forwarder/events.pb.go (6)
  • EventProtocolPaused (26-28)
  • EventProtocolPaused (32-32)
  • EventProtocolPaused (33-35)
  • EventProtocolUnpaused (70-72)
  • EventProtocolUnpaused (76-76)
  • EventProtocolUnpaused (77-79)
types/core/keys.go (1)
  • MaxTargetCounterparties (53-53)
controller/adapter/ibc_test.go (7)
types/core/attributes.go (1)
  • ForwardingAttributes (35-41)
api/controller/forwarding/v1/cctp.pulsar.go (3)
  • CCTPAttributes (568-582)
  • CCTPAttributes (597-597)
  • CCTPAttributes (600-602)
types/controller/forwarding/cctp.pb.go (3)
  • CCTPAttributes (29-39)
  • CCTPAttributes (43-43)
  • CCTPAttributes (44-46)
testutil/payload.go (1)
  • CreateValidIBCPacketData (36-46)
types/core/keys.go (1)
  • ModuleAddress (37-37)
types/core/orbiter.pb.go (6)
  • Payload (128-135)
  • Payload (139-139)
  • Payload (140-142)
  • Forwarding (79-91)
  • Forwarding (95-95)
  • Forwarding (96-98)
types/core/id.pb.go (2)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_IBC (71-71)
keeper/component/dispatcher/state.go (2)
keeper/component/dispatcher/pagination.go (1)
  • WithCollectionPaginationQuadPrefix (28-35)
keeper/component/dispatcher/dispatcher.go (1)
  • Dispatcher (41-50)
keeper/component/forwarder/state_test.go (3)
testutil/mocks/forwarder.go (1)
  • NewForwarderComponent (33-52)
keeper/component/forwarder/forwarder.go (1)
  • Forwarder (47-57)
types/component.go (1)
  • Forwarder (42-48)
types/core/id.go (2)
api/core/v1/id.pulsar.go (10)
  • ActionID (500-500)
  • ActionID (536-538)
  • ActionID (540-542)
  • ActionID (549-551)
  • ActionID_value (519-523)
  • ProtocolID (556-556)
  • ProtocolID (600-602)
  • ProtocolID (604-606)
  • ProtocolID (613-615)
  • ProtocolID_value (581-587)
types/core/id.pb.go (12)
  • ActionID (29-29)
  • ActionID (57-59)
  • ActionID_value (47-51)
  • ACTION_UNSUPPORTED (34-34)
  • ProtocolID (64-64)
  • ProtocolID (100-102)
  • ProtocolID_value (88-94)
  • PROTOCOL_UNSUPPORTED (69-69)
  • PROTOCOL_IBC (71-71)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_HYPERLANE (75-75)
  • PROTOCOL_INTERNAL (77-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: prepare
  • GitHub Check: build
  • GitHub Check: lint
  • GitHub Check: unit-test
🔇 Additional comments (3)
keeper/component/dispatcher/state.go (1)

1-20: License header present.

Header exists and matches policy.

As per coding guidelines

controller/adapter/ibc_test.go (2)

24-24: LGTM on new imports.

Both encoding/json and forwardingtypes are used; should pass lint.

Also applies to: 35-35


153-194: Enforce CCTPAttributes validation in execution
Parser accepts incomplete CCTPAttributes; confirm controller/forwarding/cctp.go’s ValidateAttributes (invoked in executeForwarding) runs and rejects missing fields (e.g. DestinationDomain) before use.

Comment thread keeper/component/dispatcher/state.go
Comment thread types/core/id.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
controller/adapter/ibc_test.go (1)

184-184: Critical: Extra closing brace causes syntax error.

Line 184 contains an extra } that doesn't match any opening brace. The if-else block starting at line 170 is already properly closed at line 183, making this brace extraneous.

Apply this diff to remove the extra brace:

 					}
 				}
 			}
-		}
 		})
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13cb53a and 4b1b839.

📒 Files selected for processing (4)
  • controller/action/fee.go (1 hunks)
  • controller/adapter/ibc_test.go (5 hunks)
  • keeper/component/adapter/adapter.go (1 hunks)
  • keeper/component/forwarder/forwarder.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • keeper/component/adapter/adapter.go
  • keeper/component/forwarder/forwarder.go
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • controller/action/fee.go
  • controller/adapter/ibc_test.go
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Write unit tests using the testCases pattern
Name each test case as "success - " for success cases and "error - " for error cases; omit the prefix when no error is tested
For error-checking cases, include an expError string field in the test case and assert with require.ErrorContains(t, tC.expError, err)

Files:

  • controller/adapter/ibc_test.go
🧬 Code graph analysis (2)
controller/action/fee.go (1)
types/controller/action/fee.go (1)
  • BPSNormalizer (35-35)
controller/adapter/ibc_test.go (5)
types/core/attributes.go (1)
  • ForwardingAttributes (35-41)
types/controller/forwarding/cctp.pb.go (3)
  • CCTPAttributes (29-39)
  • CCTPAttributes (43-43)
  • CCTPAttributes (44-46)
testutil/payload.go (1)
  • CreateValidIBCPacketData (36-46)
types/core/orbiter.pb.go (6)
  • Payload (128-135)
  • Payload (139-139)
  • Payload (140-142)
  • Forwarding (79-91)
  • Forwarding (95-95)
  • Forwarding (96-98)
types/core/id.pb.go (1)
  • PROTOCOL_CCTP (73-73)
🪛 GitHub Actions: Lint codebase
controller/adapter/ibc_test.go

[error] 184-184: syntax error: unexpected newline in argument list; possibly missing comma or )

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: prepare
  • GitHub Check: build
  • GitHub Check: unit-test
🔇 Additional comments (3)
controller/adapter/ibc_test.go (2)

167-167: LGTM: Improved error assertion.

Using require.NoError with a descriptive message is clearer than the previous assertion, especially since no error is expected at parser creation.


178-182: LGTM: Cleaner PreActions validation logic.

The refactored validation is more straightforward:

  • Unconditionally checks length first
  • Only validates content when expected PreActions exist

This is more maintainable than the previous nested nil/non-nil checks.

controller/action/fee.go (1)

243-243: Approve – BPSNormalizer consistently migrated to actiontypes
Search confirms removal of all core.BPSNormalizer references and uniform use of actiontypes.BPSNormalizer = 10000 in code and tests.

Comment thread controller/adapter/ibc_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
types/core/id_test.go (1)

162-165: Consider making the default protocol test more explicit.

The test case relies on the zero value of protocolID to test the default/unspecified protocol behavior. While this is correct (zero value falls through to the default case in the switch statement), explicitly setting it would make the test intent clearer.

Consider applying this diff for clarity:

 {
-    name:     "error - with default protocol ID",
-    id:       "12345",
-    expError: "invalid counterparty ID",
+    name:       "error - with default protocol ID",
+    id:         "12345",
+    protocolID: core.ProtocolID(0), // or core.PROTOCOL_UNSPECIFIED if defined
+    expError:   "invalid counterparty ID",
 },
keeper/component/dispatcher/state.go (4)

180-187: Avoid second store read in pagination callback (use v).

You already have the value; avoid re-get for better performance.

Apply:

-    func(k DispatchedAmountsKey, v dispatchertypes.AmountDispatched) (*dispatchertypes.DispatchedAmountEntry, error) {
-      entry, err := d.getDispatchedAmountEntryFromKey(ctx, k)
-      if err != nil {
-        return nil, err
-      }
-      return &entry, nil
-    },
+    func(k DispatchedAmountsKey, v dispatchertypes.AmountDispatched) (*dispatchertypes.DispatchedAmountEntry, error) {
+      sourceID, err := core.NewCrossChainID(core.ProtocolID(k.K1()), k.K2())
+      if err != nil {
+        return nil, errorsmod.Wrap(err, "failed to create source cross-chain ID")
+      }
+      destID, err := core.ParseCrossChainID(k.K3())
+      if err != nil {
+        return nil, errorsmod.Wrap(err, "failed to parse destination cross-chain ID")
+      }
+      entry := dispatchertypes.DispatchedAmountEntry{
+        SourceId:         &sourceID,
+        DestinationId:    &destID,
+        Denom:            k.K4(),
+        AmountDispatched: v,
+      }
+      return &entry, nil
+    },

417-424: Avoid second store read in counts pagination callback (use v).

Use the provided value; skip an extra Get per row.

Apply:

-    func(k DispatchedCountsKey, v uint64) (*dispatchertypes.DispatchCountEntry, error) {
-      entry, err := d.getDispatchCountEntryFromKey(ctx, k)
-      if err != nil {
-        return nil, err
-      }
-      return &entry, nil
-    },
+    func(k DispatchedCountsKey, v uint64) (*dispatchertypes.DispatchCountEntry, error) {
+      sourceID, err := core.NewCrossChainID(core.ProtocolID(k.K1()), k.K2())
+      if err != nil {
+        return nil, errorsmod.Wrap(err, "failed to create source cross-chain ID")
+      }
+      destID, err := core.NewCrossChainID(core.ProtocolID(k.K3()), k.K4())
+      if err != nil {
+        return nil, errorsmod.Wrap(err, "failed to create destination cross-chain ID")
+      }
+      entry := dispatchertypes.DispatchCountEntry{
+        SourceId:      &sourceID,
+        DestinationId: &destID,
+        Count:         v,
+      }
+      return &entry, nil
+    },

78-79: Naming consistency: use “cross_chain_id” instead of “orbit_id”.

For index name consistency with prefixes/constants, prefer cross-chain terminology.

-            core.DispatchedAmountsName+"_by_destination_orbit_id",
+            core.DispatchedAmountsName+"_by_destination_cross_chain_id",

248-251: Include the underlying error in logs (observability).

Add err to logs and tighten messages.

-    d.logger.Error("error in dispatched amounts walking all values")
+    d.logger.Error("error walking all dispatched amounts", "error", err)
-    d.logger.Error("error in dispatchedCounts walking all values")
+    d.logger.Error("error walking all dispatched counts", "error", err)

Also applies to: 399-401

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b1b839 and b9b7099.

📒 Files selected for processing (3)
  • controller/adapter/ibc_test.go (5 hunks)
  • keeper/component/dispatcher/state.go (3 hunks)
  • types/core/id_test.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • controller/adapter/ibc_test.go
🧰 Additional context used
📓 Path-based instructions (2)
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Write unit tests using the testCases pattern
Name each test case as "success - " for success cases and "error - " for error cases; omit the prefix when no error is tested
For error-checking cases, include an expError string field in the test case and assert with require.ErrorContains(t, tC.expError, err)

Files:

  • types/core/id_test.go
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • types/core/id_test.go
  • keeper/component/dispatcher/state.go
🧬 Code graph analysis (2)
types/core/id_test.go (2)
types/core/id.pb.go (4)
  • ProtocolID (64-64)
  • ProtocolID (100-102)
  • PROTOCOL_CCTP (73-73)
  • PROTOCOL_IBC (71-71)
types/core/id.go (2)
  • MaxCounterpartyIDLength (34-34)
  • ValidateCounterpartyID (152-183)
keeper/component/dispatcher/state.go (3)
types/component/dispatcher/dispatcher.pb.go (9)
  • DispatchedAmountEntry (75-80)
  • DispatchedAmountEntry (84-84)
  • DispatchedAmountEntry (85-87)
  • AmountDispatched (33-38)
  • AmountDispatched (42-42)
  • AmountDispatched (43-45)
  • DispatchCountEntry (145-149)
  • DispatchCountEntry (153-153)
  • DispatchCountEntry (154-156)
keeper/component/dispatcher/pagination.go (1)
  • WithCollectionPaginationQuadPrefix (28-35)
keeper/component/dispatcher/dispatcher.go (1)
  • Dispatcher (41-50)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build
  • GitHub Check: prepare
  • GitHub Check: unit-test
  • GitHub Check: lint
🔇 Additional comments (6)
types/core/id_test.go (3)

25-25: LGTM!

The strings import is appropriately added to support the new test case that generates long counterparty IDs using strings.Repeat.


97-99: LGTM!

The test case correctly validates that IDs with multiple colons are invalid. The descriptive name clearly indicates what's being tested, which addresses the previous review feedback about accuracy.


130-190: Well-structured test function with comprehensive coverage.

The test follows all coding guidelines:

  • Uses testCases pattern correctly
  • Follows naming conventions ("error - ...", "success - ...")
  • Includes expError field for error cases
  • Uses require.ErrorContains for assertions

The test coverage is thorough, including edge cases like maximum length boundaries, empty IDs, format validation for different protocols, and both success and error scenarios.

keeper/component/dispatcher/state.go (3)

30-31: Import OK

Needed for pagination APIs. LGTM.


205-218: Index-based pagination usage LGTM

Correct use of index and pair prefix for destination protocol ID.


442-454: Destination counts pagination LGTM

Index + pair prefix look correct; error messages are clear.

@0xstepit

Copy link
Copy Markdown
Contributor Author

Closes ENG-522

@linear

linear Bot commented Oct 13, 2025

Copy link
Copy Markdown

@0xstepit
0xstepit enabled auto-merge (squash) October 13, 2025 15:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
entrypoint/ibc_middleware.go (1)

142-142: Consider adding context to error messages.

The error messages on lines 142 and 162 could be more helpful for debugging by including the denom and chain information. Line 150-154 demonstrates a better pattern by including the actual values.

-		return "", errors.New("coin is native of source chain")
+		return "", fmt.Errorf("coin %q is native of source chain %s/%s", denom, sourcePort, sourceChannel)
-		return "", errors.New("orbiter supports only native tokens")
+		return "", fmt.Errorf("orbiter supports only native tokens, got non-native denom trace: %q", unprefixedDenom)

Also applies to: 162-162

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9b7099 and b385af6.

📒 Files selected for processing (3)
  • entrypoint/ibc_middleware.go (5 hunks)
  • keeper/component/adapter/adapter.go (2 hunks)
  • keeper/component/dispatcher/dispatcher.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • keeper/component/dispatcher/dispatcher.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • entrypoint/ibc_middleware.go
  • keeper/component/adapter/adapter.go
🧬 Code graph analysis (1)
entrypoint/ibc_middleware.go (3)
types/core/id.go (1)
  • NewCrossChainID (122-137)
types/core/id.pb.go (1)
  • PROTOCOL_IBC (71-71)
types/core/errors.go (1)
  • ErrNonNativeCoin (36-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: prepare
🔇 Additional comments (4)
keeper/component/adapter/adapter.go (2)

264-264: LGTM!

The rename from clearOrbiterBalances (plural) to clearOrbiterBalance (singular) accurately reflects that the method operates on a single denomination. This improves code clarity and consistency.

Also applies to: 271-271, 275-275


233-238: Approve fail-safe GetParams error handling — The logging-and-default-zero-size pattern aligns with genesis.go, preserving empty-payload transfers and rejecting non-empty payloads on errors.

entrypoint/ibc_middleware.go (2)

85-90: LGTM! Proper IBC counterparty identifier construction.

The change to derive ibcCounterpartyID using GetDenomPrefix follows the IBC denom prefix pattern correctly. Using the destination port and channel is appropriate since this represents the source chain's channel identifier on Noble.


96-96: LGTM! Clear documentation of sentinel error behavior.

The comment effectively documents the special handling of ErrNoOrbiterPacket, making the control flow more understandable.

Comment thread entrypoint/ibc_middleware.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
keeper/component/dispatcher/dispatcher.go (1)

231-244: Consider harmonizing error handling patterns.

While the structured logging and error wrapping here are appropriate, there's an inconsistency with dispatchActions (lines 169-186), which wraps and returns errors without logging them first.

If forwarding errors are considered more critical than action errors and warrant Error-level logging at this layer, the current approach is fine. Otherwise, consider applying the same error handling pattern to both methods for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b385af6 and 888d4aa.

📒 Files selected for processing (1)
  • keeper/component/dispatcher/dispatcher.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • keeper/component/dispatcher/dispatcher.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: prepare
  • GitHub Check: build
  • GitHub Check: lint
  • GitHub Check: unit-test
🔇 Additional comments (1)
keeper/component/dispatcher/dispatcher.go (1)

204-217: LGTM! Improved error handling with structured logging.

The addition of structured logging with key-value pairs and error wrapping using errorsmod.Wrapf improves observability and provides better context for debugging. The protocol ID is properly included in both the log entry and the wrapped error message.

@0xstepit
0xstepit merged commit 81da84f into main Oct 13, 2025
9 of 10 checks passed
@0xstepit
0xstepit deleted the stepit/halborn-audit branch October 13, 2025 15:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
entrypoint/ibc_middleware.go (1)

140-166: Prefer typed/sentinel errors in recoverNativeDenom for consistent classification.

Currently returns plain errors/fmt.Errorf. Consider using errorsmod with sentinels (e.g., core.ErrNonNativeCoin, an “invalid denom/prefix” sentinel) so upstream can use errors.Is/As and so acknowledgements carry consistent context across the stack.

Example (adjust sentinel names to your taxonomy):

-		return "", errors.New("coin is native of source chain")
+		return "", errorsmod.Wrap(core.ErrNonNativeCoin, "coin is native of source chain")

-		return "", fmt.Errorf(
-			"denom %q missing expected IBC prefix %q",
-			denom,
-			voucherPrefix,
-		)
+		return "", errorsmod.Wrapf(core.ErrInvalidDenom, "denom %q missing expected IBC prefix %q", denom, voucherPrefix)

-		return "", errors.New("orbiter supports only native tokens")
+		return "", errorsmod.Wrap(core.ErrNonNativeCoin, "orbiter supports only native tokens")

Also consider aligning the message phrasing with the wrapper at Line 112 (“non-native coin”) for clarity.

I can help introduce/standardize the sentinels in core and update call sites if desired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 888d4aa and 6c0c1c4.

📒 Files selected for processing (2)
  • entrypoint/ibc_middleware.go (5 hunks)
  • types/core/errors.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Go code must be formatted and pass golangci-lint
All Go files must include license headers

Files:

  • types/core/errors.go
  • entrypoint/ibc_middleware.go
🧠 Learnings (1)
📚 Learning: 2025-10-13T11:49:11.257Z
Learnt from: MalteHerrmann
PR: noble-assets/orbiter#49
File: controller/adapter/ibc.go:74-81
Timestamp: 2025-10-13T11:49:11.257Z
Learning: In the orbiter codebase, when packet parsing determines a packet is not intended for the orbiter module (e.g., invalid ICS-20 data or wrong receiver), return a typed sentinel error `core.ErrNoOrbiterPacket` instead of (nil, nil). Callers should check with `errors.Is(err, core.ErrNoOrbiterPacket)` to implement fallback behavior, avoiding nil pointer panics and making intent explicit.

Applied to files:

  • types/core/errors.go
🧬 Code graph analysis (2)
types/core/errors.go (1)
types/core/keys.go (1)
  • ModuleName (30-30)
entrypoint/ibc_middleware.go (2)
types/core/id.go (1)
  • NewCrossChainID (122-137)
types/core/id.pb.go (1)
  • PROTOCOL_IBC (71-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build
  • GitHub Check: prepare
  • GitHub Check: unit-test
  • GitHub Check: lint
🔇 Additional comments (4)
types/core/errors.go (1)

36-36: Confirm no external dependencies on changed error code. Internal checks use errors.Is and no numeric code comparisons were found; verify that no external clients, indexers, or monitoring tools depend on the previous code (12) for ErrNoOrbiterPacket.

entrypoint/ibc_middleware.go (3)

96-103: Good: fall through to ICS20 app on ErrNoOrbiterPacket.

Clear, symmetric behavior; wrapped errors continue to be handled via errors.Is.


111-113: Good: preserve error chain when surfacing “non-native coin”.

Switching to errorsmod.Wrap avoids losing the original error chain (addresses earlier feedback).


85-91: Verify need for trailing-sllash normalization in CounterpartyId
I didn’t find NewCrossChainID or a Validate() enforcing CounterpartyId format—please confirm if the trailing “/” from transfertypes.GetDenomPrefix must be trimmed. Example normalization:

ibcCounterpartyID := strings.TrimSuffix(
    transfertypes.GetDenomPrefix(packet.DestinationPort, packet.DestinationChannel),
    "/",
)

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

Labels

bug Something isn't working improvement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants