@@ -30,6 +30,7 @@ abstract contract ERC7984ERC20Wrapper is ERC7984, IERC1363Receiver {
3030 event UnwrapFinalized (address indexed receiver , euint64 encryptedAmount , uint64 cleartextAmount );
3131
3232 error InvalidUnwrapRequest (euint64 amount );
33+ error ERC7984TotalSupplyOverflow ();
3334
3435 constructor (IERC20 underlying_ ) {
3536 _underlying = underlying_;
@@ -45,28 +46,10 @@ abstract contract ERC7984ERC20Wrapper is ERC7984, IERC1363Receiver {
4546 }
4647 }
4748
48- /// @inheritdoc ERC7984
49- function decimals () public view virtual override returns (uint8 ) {
50- return _decimals;
51- }
52-
53- /**
54- * @dev Returns the rate at which the underlying token is converted to the wrapped token.
55- * For example, if the `rate` is 1000, then 1000 units of the underlying token equal 1 unit of the wrapped token.
56- */
57- function rate () public view virtual returns (uint256 ) {
58- return _rate;
59- }
60-
61- /// @dev Returns the address of the underlying ERC-20 token that is being wrapped.
62- function underlying () public view returns (IERC20 ) {
63- return _underlying;
64- }
65-
6649 /**
6750 * @dev `ERC1363` callback function which wraps tokens to the address specified in `data` or
6851 * the address `from` (if no address is specified in `data`). This function refunds any excess tokens
69- * sent beyond the nearest multiple of {rate}. See {wrap} from more details on wrapping tokens.
52+ * sent beyond the nearest multiple of {rate} to `from` . See {wrap} from more details on wrapping tokens.
7053 */
7154 function onTransferReceived (
7255 address /*operator*/ ,
@@ -149,6 +132,61 @@ abstract contract ERC7984ERC20Wrapper is ERC7984, IERC1363Receiver {
149132 emit UnwrapFinalized (to, burntAmount, burntAmountCleartext);
150133 }
151134
135+ /// @inheritdoc ERC7984
136+ function decimals () public view virtual override returns (uint8 ) {
137+ return _decimals;
138+ }
139+
140+ /**
141+ * @dev Returns the rate at which the underlying token is converted to the wrapped token.
142+ * For example, if the `rate` is 1000, then 1000 units of the underlying token equal 1 unit of the wrapped token.
143+ */
144+ function rate () public view virtual returns (uint256 ) {
145+ return _rate;
146+ }
147+
148+ /// @dev Returns the address of the underlying ERC-20 token that is being wrapped.
149+ function underlying () public view returns (IERC20 ) {
150+ return _underlying;
151+ }
152+
153+ /**
154+ * @dev Returns the underlying balance divided by the {rate}, a value greater or equal to the actual
155+ * {confidentialTotalSupply}.
156+ *
157+ * NOTE: The return value of this function can be inflated by directly sending underlying tokens to the wrapper contract.
158+ * Reductions will lag compared to {confidentialTotalSupply} since it is updated on {unwrap} while this function updates
159+ * on {finalizeUnwrap}.
160+ */
161+ function totalSupply () public view virtual returns (uint256 ) {
162+ return underlying ().balanceOf (address (this )) / rate ();
163+ }
164+
165+ /// @dev Returns the maximum total supply of wrapped tokens supported by the encrypted datatype.
166+ function maxTotalSupply () public view virtual returns (uint256 ) {
167+ return type (uint64 ).max;
168+ }
169+
170+ /**
171+ * @dev This function must revert if the new {confidentialTotalSupply} is invalid (overflow occurred).
172+ *
173+ * NOTE: Overflow can be detected here since the wrapper holdings are non-confidential. In other cases, it may be impossible
174+ * to infer total supply overflow synchronously. This function may revert even if the {confidentialTotalSupply} did
175+ * not overflow.
176+ */
177+ function _checkConfidentialTotalSupply () internal virtual {
178+ if (totalSupply () > maxTotalSupply ()) {
179+ revert ERC7984TotalSupplyOverflow ();
180+ }
181+ }
182+
183+ function _update (address from , address to , euint64 amount ) internal virtual override returns (euint64) {
184+ if (from == address (0 )) {
185+ _checkConfidentialTotalSupply ();
186+ }
187+ return super ._update (from, to, amount);
188+ }
189+
152190 function _unwrap (address from , address to , euint64 amount ) internal virtual {
153191 require (to != address (0 ), ERC7984InvalidReceiver (to));
154192 require (from == msg .sender || isOperator (from, msg .sender ), ERC7984UnauthorizedSpender (from, msg .sender ));
0 commit comments