Skip to content

M-M09: reject asset decimals exceeding its token's decimals#659

Merged
philanton merged 1 commit intofix/audit-findingsfrom
fix/clearnode-m-09
Apr 9, 2026
Merged

M-M09: reject asset decimals exceeding its token's decimals#659
philanton merged 1 commit intofix/audit-findingsfrom
fix/clearnode-m-09

Conversation

@philanton
Copy link
Copy Markdown
Contributor

@philanton philanton commented Apr 8, 2026

Description

GetAssetDecimals and GetTokenDecimals read from two independent maps in the memory store, populated from separate config fields with no requirement that they are the same. The asset-level field is a single value per asset symbol, while GetTokenDecimals is keyed on blockchainID and tokenAddress, meaning the same asset can have different precision on different chains.
This is also problematic in escrow flows, where the same transition amount may need to be represented on both the home and escrow ledgers. If those two token representations use different decimals, the request can pass transition validation under the asset-level precision and fail later when one of the ledgers is converted using the lower token precision.
Consequently, valid operations can be rejected or accepted only to fail later in the signing flow.

Summary by CodeRabbit

  • Bug Fixes
    • Added validation to ensure asset decimal values do not exceed their associated token decimal values. Invalid configurations are now rejected with detailed error messages during asset verification and caching.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

The changes introduce a new validation rule that ensures asset decimals do not exceed associated token decimals. This validation is enforced in two layers: the asset configuration verification in clearnode and the SDK asset cache population, with corresponding test coverage for both success and failure paths.

Changes

Cohort / File(s) Summary
Configuration Validation
clearnode/store/memory/asset_config.go, clearnode/store/memory/asset_config_test.go
Added decimals validation to verifyAssetsConfig that returns an error if asset decimals exceed token decimals. Includes two new test cases: one verifying the error when asset decimals (8) exceed token decimals (6), and one confirming success when both are equal (6).
SDK Asset Caching
sdk/go/asset_cache.go, sdk/go/asset_cache_test.go
Integrated decimals validation into clientAssetStore.populateCache to reject assets before caching if their decimals exceed any associated token's decimals. Added new test case demonstrating the validation error scenario with USDC asset (18 decimals) and token (6 decimals).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • ihsraham
  • dimast-x

Poem

🐰 A hop, skip, and decimal check—
Asset and token must align,
No excess zeros for a wreck,
Validation makes them shine!
When decimals dance hand in hand,
The cache holds fortune vast and grand. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 accurately describes the main validation being added: rejecting assets whose decimal precision exceeds their associated token's decimal precision.

✏️ 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/clearnode-m-09

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.

@nksazonov
Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
clearnode/store/memory/asset_config_test.go (1)

100-123: Consider adding a test case for asset decimals less than token decimals.

The current tests cover the failure case (asset > token) and boundary case (asset == token), but don't explicitly test the valid scenario where asset decimals are less than token decimals.

Based on learnings, the YUSD test token has different decimals across chains (6 on Sepolia, 8 on Amoy), so an asset with Decimals: 6 paired with a token having Decimals: 8 should be valid.

🧪 Suggested additional test case
+	// Test asset decimals less than token decimals (should pass)
+	t.Run("asset decimals less than token decimals", func(t *testing.T) {
+		cfg := AssetsConfig{
+			Assets: []AssetConfig{
+				{
+					Name:                  "USD Coin",
+					Symbol:                "USDC",
+					Decimals:              6,
+					SuggestedBlockchainID: 1,
+					Tokens: []TokenConfig{
+						{
+							Name:         "USD Coin",
+							Symbol:       "USDC",
+							BlockchainID: 1,
+							Address:      "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
+							Decimals:     8,
+						},
+					},
+				},
+			},
+		}
+		err := verifyAssetsConfig(&cfg)
+		require.NoError(t, err)
+	})
+
 	// Test custom symbol for token (inherits from asset when empty)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clearnode/store/memory/asset_config_test.go` around lines 100 - 123, Add a
new test in asset_config_test.go that verifies the valid scenario where an
asset's Decimals is less than its token's Decimals: create an AssetsConfig with
one AssetConfig (e.g., Decimals: 6) containing a TokenConfig with higher
Decimals (e.g., 8), call verifyAssetsConfig(&cfg) and assert require.NoError(t,
err); place the test alongside the existing cases and name it "asset decimals
less than token decimals" to target the verifyAssetsConfig validation logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@clearnode/store/memory/asset_config_test.go`:
- Around line 100-123: Add a new test in asset_config_test.go that verifies the
valid scenario where an asset's Decimals is less than its token's Decimals:
create an AssetsConfig with one AssetConfig (e.g., Decimals: 6) containing a
TokenConfig with higher Decimals (e.g., 8), call verifyAssetsConfig(&cfg) and
assert require.NoError(t, err); place the test alongside the existing cases and
name it "asset decimals less than token decimals" to target the
verifyAssetsConfig validation logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 857d3d39-b347-4d81-bf59-891a6a6e82c5

📥 Commits

Reviewing files that changed from the base of the PR and between 38d2ad1 and 957b1ea.

📒 Files selected for processing (4)
  • clearnode/store/memory/asset_config.go
  • clearnode/store/memory/asset_config_test.go
  • sdk/go/asset_cache.go
  • sdk/go/asset_cache_test.go

@philanton philanton merged commit 4f3ab2c into fix/audit-findings Apr 9, 2026
3 checks passed
@philanton philanton deleted the fix/clearnode-m-09 branch April 9, 2026 11:38
nksazonov added a commit that referenced this pull request Apr 16, 2026
H-H01: fix(contracts): disallow challenge with CLOSE or FIN_MIG intents (#631)

H-M01: fix(contracts/ChannelHub): remove transferred amount check (#636)

fix(contracts/ChannelHub): allow unblocking escrow ops after migration (#637)

M-C01: feat(contracts): add token check between states (#639)

H-L03: fix(contracts/ChannelHub): skip disputed escrow during purge (#640)

M-H04: feat(contracts/ChannelHub): purge during escrow challenge finalization, count both skip and purge (#641)

M-M02: fix(contracts): require zero allocs on close (#643)

M-C02: fix(rpc/core): apply finalize escrow deposit correctly (#644)

H-L02: fix(contracts/ChannelHub): revert on withdrawFromVault failure (#651)

M-H03: fix(clearnode): log correct fields on failure (#647)

M-C03: fix(pkg/core): disallow negative amount transitions (#645)

H-L01: fix(contracts/ChannelHub): add CH address to prevent val addition replay (#650)

M-H06(clearnode): restrict max channel challenge duration (#654)

M-M03(clearnode): revert EscrowLock on insufficient home user balance (#655)

M-M04(clearnode): support default signer even if it is not approved (#656)

M-M05(clearnode): require correct intent on FinalizeEscrowWithdrawal (#657)

M-M09: reject asset decimals exceeding its token's decimals (#659)

M-L01: return correct errors during state advancement validation (#660)

M-L03: limit number of related ids per session key state (#662)

M-I02: normalize input hex addresses (#663)

M-H01: feat(contracts/ChannelHub): restrict to one node (#649)

M-H07: fix(contracts/ChannelHub): emit stored, not arbitrary candidate state (#664)

M-I01: feat(contracts/ChannelHub): remove updateLastState flag (#665)

H-L06: fix(contracts/ChannelHub): remove payable from methods, clarify in create (#666)

H-L09: feat(contracts/ChannelEngine): add non-home migration version check (#669)

YNU-839: fix blockchain listener lifecycle (#658)

M-H09: use channel signer for all channel state node sigs (#667)

H-L07: fix(contracts/ChannelHub): restrict createChannel to non-existing channels (#668)

H-I02: docs(contracts): add a note that rebasing tokens are not supported (#670)

H-I03: fix(contracts/ChannelHub): use CIE pattern in depositToHub (#671)

M-H11: revert empty signatures on quorum verification (#672)

M-H11: reject issuance of receiver state during escrow ops (#674)

H-I01: docs(contracts): note that fee-on-transfer tokens are not supported (#675)

M-L04: docs: mention liquidity monitoring (#677)

fix(contracts/ChannelHub): fix initialize escrow deposit dos (#679)

M-H08: enforce strict transition ordering after MutualLock and EscrowLock (#680)

fix: run forge fmt (#681)

M-L05: docs(contracts): document native token deposits (#685)

fix(clearnode): resolve a set of audit findings (#686)

M-H13: feat(contract): add validateChallengeSignature, revert in SK validator (#688)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants