OpenZeppelin / OpenZeppelin/compact-contracts
H-03: Missing Contract Commitment Claim When Recipient is a Contract
- Dominant language
- TypeScript
- Stars
- 55
- Forks
- 29
- Avg merge
- 5d 7h
- Merged PRs (30d)
- 25
Description
H-03 Missing Contract Commitment Claim When Recipient is a Contract
Severity: High
Source: Midnight Foundation #02 — OpenZeppelin Compact Contracts Audit, Release 0.3.0-alpha.1 (2026-08-18)
The _mint circuit and _burn circuit in the NativeShieldedTokenCore contract mint tokens or refund tokens via mintShieldedToken/sendImmediateShielded to a caller-supplied recipient (mint recipient or refund address), which is typed as Either<ZswapCoinPublicKey, ContractAddress>. When refundTo is a plain public key, this is a valid, self-contained Zswap output.
However, when refundTo resolves to right<...>(ContractAddress), the resulting coin commitment is contract-associated and, per the ledger's well-formedness rules, must be claimed as a shielded receive by that contract in the same transaction/segment via kernel.claimContractCall - otherwise the transaction is rejected.
Consider accepting the target contract's entry point and call-randomness as additional witness/public inputs, computing transientCommit, and calling kernel.claimContractCall as per this example. Alternatively, consider only accepting ZswapCoinPublicKey (via left<...>) as the recipient if contract-address refunds are not a supported use case, to prevent constructing transactions that will always fail.
Contributor 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.
Assessment
This issue has not been assessed yet.