Skip to content

fix: distribution precompile 32-byte withdraw address inflates native supply#340

Merged
mattkii merged 1 commit into
mainfrom
fix/distribution-32byte-withdraw
Jun 22, 2026
Merged

fix: distribution precompile 32-byte withdraw address inflates native supply#340
mattkii merged 1 commit into
mainfrom
fix/distribution-32byte-withdraw

Conversation

@mattkii

@mattkii mattkii commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes native token supply inflation triggered through the stateful EVM precompiles
(distribution/staking/gov) when an account address is not exactly 20 bytes.

The precompiles accept an account address (e.g. the distribution withdraw address) and mirror
the resulting bank transfer into the EVM StateDB via common.BytesToAddress, which is keyed by
a 20-byte address. A longer account (e.g. a 32-byte bech32 account, module account, or CosmWasm
contract) is silently truncated to its trailing 20 bytes during mirroring, causing the StateDB
commit to mint a duplicate balance to that trailing-20-byte account and inflate native supply.

This PR introduces an evmAddressCodec wrapper (app/keepers/precompiles.go) around the
account AddressCodec used by the gov/staking precompiles. Its StringToBytes rejects any
decoded address that is not exactly 20 bytes, so non-EVM accounts can never enter a
balance-mirroring precompile flow.

NOTE: This is an in-kiichain fix and does NOT bump the cosmos/evm fork; the go.mod replace
directive remains at v0.6.0-fork.1. The related fork-side fix (KiiChain/evm#16) is an
alternative/defense-in-depth approach and is not required by this PR.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Test A — Unit test for evmAddressCodec.StringToBytes: a 20-byte account decodes
    successfully; a 32-byte account is rejected with a clear error.
  • Test B — make test-unit and make build pass.

PR Checklist:

  • Updated changelog with PR's intent
  • Lint with make lint-fix

@mattkii mattkii requested a review from jhelison as a code owner June 12, 2026 14:36
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5e1af429-c191-415b-b813-cef85d897b97

📥 Commits

Reviewing files that changed from the base of the PR and between 03aa187 and fb20372.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • app/keepers/precompiles.go
  • app/keepers/precompiles_test.go
  • tests/e2e/genesis.go
💤 Files with no reviewable changes (1)
  • tests/e2e/genesis.go
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/keepers/precompiles.go

Walkthrough

This PR introduces two independent changes. First, a new evmAddressCodec type is added to app/keepers/precompiles.go that wraps the standard address codec and validates decoded addresses are exactly 20 bytes before they enter the address-to-bytes decoding path used by balance-mirroring precompiles. Second, the e2e genesis test configuration in tests/e2e/genesis.go removes several message type paths (authz, feegrant, IBC transfer, and Tendermint liquidity operations) from the ICA host allowed messages list.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing native token supply inflation in the distribution precompile caused by 32-byte withdraw addresses.
Description check ✅ Passed The description is directly related to the changeset, explaining the root cause, solution, and testing approach for the supply inflation bug fix.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/distribution-32byte-withdraw

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.

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/keepers/precompiles.go (1)

92-96: 💤 Low value

Consider documenting the validation bypass risk.

The WithAddressCodec option allows callers to override the default evmAddressCodec wrapper, which bypasses the 20-byte validation. Consider adding a comment warning that custom codecs must ensure addresses are EVM-compatible (20 bytes) to prevent the balance-mirroring inflation bug.

📝 Suggested documentation enhancement
 // WithAddressCodec returns the function to access the with address codec
+// WARNING: Custom codecs must ensure addresses are exactly 20 bytes (EVM-compatible)
+// to prevent balance mirroring from inflating native supply. Use evmAddressCodec or
+// equivalent validation.
 func WithAddressCodec(codec address.Codec) Option {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/keepers/precompiles.go` around lines 92 - 96, Add a short comment above
WithAddressCodec explaining that supplying a custom address.Codec will bypass
the package's default evmAddressCodec 20-byte validation and that custom codecs
must ensure addresses are EVM-compatible (exactly 20 bytes) to avoid
balance-mirroring/inflation issues; reference the Optionals.AddressCodec field
and evmAddressCodec in the comment so callers know which validation is being
bypassed and what guarantee they must preserve.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/keepers/precompiles.go`:
- Line 56: The PR introduced application logic (evmAddressCodec type and its use
in defaultOptionals) despite claiming a dependency-only change; either remove
the new runtime validation and restore AddressCodec to its previous codec (undo
evmAddressCodec and the wrapping in defaultOptionals) so the PR truly remains
dependency-only, or if the validation is intended, extract the evmAddressCodec
and the defaultOptionals modification into a separate, clearly-described PR and
update this PR’s description and tests to reflect the behavioral change
(including adjusting claims about building against the bumped fork and relevant
regression tests); locate and act on the evmAddressCodec type and its usage in
defaultOptionals in precompiles.go to implement the chosen path.

---

Nitpick comments:
In `@app/keepers/precompiles.go`:
- Around line 92-96: Add a short comment above WithAddressCodec explaining that
supplying a custom address.Codec will bypass the package's default
evmAddressCodec 20-byte validation and that custom codecs must ensure addresses
are EVM-compatible (exactly 20 bytes) to avoid balance-mirroring/inflation
issues; reference the Optionals.AddressCodec field and evmAddressCodec in the
comment so callers know which validation is being bypassed and what guarantee
they must preserve.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a7387b83-768d-456b-953c-e99b18e501ac

📥 Commits

Reviewing files that changed from the base of the PR and between f632e7f and 03aa187.

📒 Files selected for processing (2)
  • app/keepers/precompiles.go
  • tests/e2e/genesis.go
💤 Files with no reviewable changes (1)
  • tests/e2e/genesis.go

Comment thread app/keepers/precompiles.go
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mattkii mattkii changed the title fix: distribution precompile 32-byte withdraw address inflates native… fix: distribution precompile 32-byte withdraw address inflates native supply Jun 12, 2026
@mattkii mattkii force-pushed the fix/distribution-32byte-withdraw branch from 03aa187 to 2e480c8 Compare June 12, 2026 14:56
@mattkii mattkii marked this pull request as draft June 12, 2026 15:15
@mattkii mattkii force-pushed the fix/distribution-32byte-withdraw branch 2 times, most recently from 7f9cded to dac926f Compare June 12, 2026 20:50
# Description

Adds Hacken's Audit results and overview on Kiichain

## Type of change
- Documentation (updates documentation on the project)
@mattkii mattkii force-pushed the fix/distribution-32byte-withdraw branch from dac926f to fb20372 Compare June 12, 2026 21:17
@mattkii mattkii marked this pull request as ready for review June 12, 2026 21:50
@mattkii mattkii merged commit 79e2de7 into main Jun 22, 2026
10 checks passed
@mattkii mattkii deleted the fix/distribution-32byte-withdraw branch June 22, 2026 03:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants