ZRC20 default liquidity cap miscomputed (decimals vs 10^decimals)
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 85/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- go
- Domain
- blockchain
Research direction
The buggy default liquidity cap calculation is in x/fungible/keeper/evm.go lines 172-175, with the expected scaling rule defined in x/fungible/types/zrc20.go. Apply the big.Int.Exp(10, decimals) pattern from the issue to fix the logic, then add unit tests for DeployZRC20Contract with liquidityCap == nil for 6, 8, and 18 decimal tokens to confirm the cap is computed correctly. Run the x/fungible package test suite to verify no regressions.
Written by the indexing model from the issue text.
Description
Summary
When MsgDeployFungibleCoinZRC20 omits liquidity_cap, the default is computed as DefaultLiquidityCap (1000) * decimals instead of DefaultLiquidityCap * 10^decimals as documented on the constant. The resulting cap is 18000 wei for an 18-decimal token (e.g. ETH), 6000 wei for a 6-decimal token (e.g. USDC), and 8000 wei for an 8-decimal token (e.g. WBTC). getAndCheckZRC20 rejects any non-dust deposit with ErrForeignCoinCapReached, effectively bricking the token until an operational-policy tx resets the cap.
Root cause
x/fungible/keeper/evm.go:172-175:
if liquidityCap == nil {
liquidityCap = ptr.Ptr(sdkmath.NewUint(types.DefaultLiquidityCap).MulUint64(uint64(newCoin.Decimals)))
}
newCoin.Decimals is the raw decimal count, not 10^decimals. The comment on DefaultLiquidityCap in x/fungible/types/zrc20.go:5-8 says the on-chain value should be value * 10^decimals.
Reachability
The default-cap branch is only reachable through MsgDeployFungibleCoinZRC20, which is in AdminPolicyMessages (x/authority/types/authorization_list.go:36). MsgWhitelistAsset already wraps the cap via ptr.Ptr(msg.LiquidityCap) before calling the keeper, so it never hits the buggy branch. The bug is admin-error class, recoverable via MsgUpdateZRC20LiquidityCap (operational policy).
Fix
Mirror the existing big.Int.Exp(10, decimals) pattern from gas_coin_and_pool.go:84:
if liquidityCap == nil {
tenPow := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(newCoin.Decimals)), nil)
liquidityCap = ptr.Ptr(sdkmath.NewUintFromBigInt(tenPow).MulUint64(types.DefaultLiquidityCap))
}
Add a unit test that exercises DeployZRC20Contract with liquidityCap == nil for decimals 6, 8, and 18 to lock in the correct default and prevent regression.
Optional hardening: tighten MsgDeployFungibleCoinZRC20.ValidateBasic to reject LiquidityCap == nil outright.
History
Introduced in commit 367e4aa4f (Cosmos v0.50 upgrade, PR #3357, 2025-01-24). Has been in main since January 2025; the default-cap branch is untested.
Severity
Low. Admin-gated, recoverable in one transaction by the same policy group, no permanent fund loss under normal operation.
References
- HackenProof report: https://dashboard.hackenproof.com/manager/companies/zetachain/zetachain-blockchain-software/reports/ZCNode-263
- Local analysis:
hackeproof/analysis/blockchain/report_ZCNode-263.md
- Dominant language
- Go
- Stars
- 202
- Forks
- 181
- Avg merge
- 17h 6m
- Merged PRs (30d)
- 2
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- No contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from zeta-chain/node
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
zeta-chain/node#4622 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
zeta-chain/node#4610 ·
-
bug_bounty zetacore
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
zeta-chain/node#4607 ·
-
bug_bounty zetaclient
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
zeta-chain/node#4603 ·
-
MsgUpdateOperationalChainParams missing range validation can panic zetaclient outbound schedulerOpenbug_bounty zetacore
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
zeta-chain/node#4602 ·
Similar issues
-
needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
WriterSetTimes: the UTIME_NOW check fails when the kernel uses its coarse clockPossibly taken @JakeChampion claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
JakeChampion/lang#14224 ·
Maintainers usually reply within 1 day
-
agent-butler-finding bug
Difficulty 1/5 Under an hour Newbie friendliness 88/100
jordansmall/spindrift#6391 ·
Maintainers usually reply within 1 day
-
common.Retry: data race on the shared response/err variables when the request context ends mid-attempt (v65.127.0, v65.128.0)Possibly taken @kmohit00 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
oracle/oci-go-sdk#676 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
SAP/crossplane-provider-btp#1175 ·
Maintainers usually reply within 1 day