-
Notifications
You must be signed in to change notification settings - Fork 32
Revert when wrapper is full #268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revert when wrapper is full #268
Conversation
✅ Deploy Preview for confidential-tokens ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughRefactored minting logic in ERC7984ERC20Wrapper by re-introducing public accessors (decimals, rate, underlying), adding totalSupply() and internal _mint() functions with overflow checks, and simplifying type conversions by removing FHE wrapping in mint paths. Added tests validating maximum representable amounts and overflow behavior. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
Comment |
There was a problem hiding this comment.
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)
contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol (1)
161-164: Consider expanding the comment to clarify the invariant.The overflow check works because both call sites (
wrapandonTransferReceived) transfer the underlying tokens before calling this function. A more descriptive comment could help future maintainers understand this invariant.function _mint(address to, uint64 amount) internal virtual { - totalSupply(); // check that total supply doesn't overflow + // Revert if new total supply would overflow uint64. + // Requires: underlying tokens already transferred before this call. + totalSupply(); _mint(to, FHE.asEuint64(amount)); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol(4 hunks)test/token/ERC7984/extensions/ERC7984Wrapper.test.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-22T09:21:34.470Z
Learnt from: james-toussaint
Repo: OpenZeppelin/openzeppelin-confidential-contracts PR: 160
File: test/token/ERC7984/extensions/ERC7984Rwa.test.ts:474-479
Timestamp: 2025-09-22T09:21:34.470Z
Learning: In ERC7984Freezable force transfers, the frozen balance is reset to the new balance only when the transferred amount exceeds the available balance (balance - frozen). If the transferred amount is within the available balance, the frozen amount remains unchanged. This is implemented via FHE.select(FHE.gt(encryptedAmount, confidentialAvailable(account)), confidentialBalanceOf(account), frozen).
Applied to files:
contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol
📚 Learning: 2025-09-15T14:43:25.644Z
Learnt from: arr00
Repo: OpenZeppelin/openzeppelin-confidential-contracts PR: 186
File: contracts/token/ERC7984/extensions/ERC7984Omnibus.sol:140-167
Timestamp: 2025-09-15T14:43:25.644Z
Learning: In ERC7984Omnibus callback functions like confidentialTransferFromAndCallOmnibus, the encrypted sender and recipient addresses are not passed to the callback recipient - only the standard transfer parameters (omnibusFrom, omnibusTo, amount, data) are passed. The ACL grants for the encrypted addresses are for omnibus event emission and future access, not for callback usage.
Applied to files:
contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol
⏰ 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: Redirect rules - confidential-tokens
- GitHub Check: tests
- GitHub Check: coverage
- GitHub Check: slither
🔇 Additional comments (5)
contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol (3)
53-72: LGTM!The updated flow correctly handles the minting after excess refund. The
SafeCast.toUint64ensures the wrapped amount fits withinuint64bounds, and the subsequenttotalSupply()check in_mintvalidates the post-transfer state since tokens are already in the contract when this callback executes.
79-85: LGTM!The ordering is correct: underlying tokens are transferred first (line 81), so when
_mintcallstotalSupply(), the balance already reflects the incoming tokens. This ensures the overflow check validates the post-mint state.
152-159: LGTM!The implementation correctly uses
SafeCast.toUint64which provides the overflow protection mechanism. The NOTE appropriately documents that direct transfers can inflate this value.test/token/ERC7984/extensions/ERC7984Wrapper.test.ts (2)
85-104: LGTM!The max amount calculation is correct:
(2^64 - 1) / 10^6yields the maximum value that, when scaled to 18 decimals and divided by the rate, still fits inuint64. The test properly verifies both callback and direct wrap paths.
106-119: LGTM!The test correctly validates that wrapping
maxAmount + 1triggers an overflow. TheSafeCastOverflowedUintDowncasterror is the expected revert fromSafeCast.toUint64when the value exceedsuint64.max.
45bcb75 to
270850c
Compare
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
| * Reductions will lag compared to {confidentialTotalSupply} since it is updated on {unwrap} while this function updates | ||
| * on {finalizeUnwrap}. | ||
| */ | ||
| function totalSupply() public view virtual returns (uint256) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question than here https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/268/files#r2603361771. If kept I would (a) choose a different name (totalSupplyEstimation?) with same code or (b) call it totalUnderlyingSupply with return underlying().balanceOf(address(this)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#268 (comment) used in tandem with maxTotalSupply to understand if the wrap request will be successful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming the function is an interesting idea. @Amxx what do you think? It may be worthwhile to ensure that people don't use it without looking into the additional notes around it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong attachment to the name.
* Revert when wrapper full * up * simplify and add tests * update docs * cei * add doc * up * add custom error and fix tests * comment clarification * Rename `_checkTotalSupply` to `_checkConfidentialTotalSupply` * add changeset * Update contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com> * docs --------- Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
* Revert when wrapper full * up * simplify and add tests * update docs * cei * add doc * up * add custom error and fix tests * comment clarification * Rename `_checkTotalSupply` to `_checkConfidentialTotalSupply` * add changeset * Update contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol * docs --------- Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This PR fixes an issue where wrapping assumes that the ERC7984
_mintfunction is successful without any checks. This is not a safe assumption and can result in loss of funds if the_mintfails (would happen if the call results in overflow).This issue is fixed by checking plaintext state, which allows the contract to infer an upper bound on the confidential total supply. If the confidential total supply may overflow, the wrap transaction is reverted.
Summary by CodeRabbit
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.