@@ -64,7 +64,7 @@ pragma solidity 0.8.24;
6464import {Test} from "forge-std/Test.sol " ;
6565import {SXCEngine} from "../../src/SXCEngine.sol " ;
6666import {StableXCoin} from "../../src/StableXCoin.sol " ;
67- import {ERC20Mock } from "@openzeppelin/contracts/mocks/ERC20Mock.sol " ;
67+ import {ERC20Mock } from "@openzeppelin/contracts/mocks/token/ ERC20Mock.sol " ;
6868
6969contract Handler is Test {
7070 // ========================
@@ -77,6 +77,8 @@ contract Handler is Test {
7777 ERC20Mock public weth;
7878 ERC20Mock public wbtc;
7979
80+ uint256 MAX_DEPOSIT_SIZE = type (uint96 ).max;
81+
8082 /// @notice Initializes the handler with the deployed engine and stablecoin
8183 /// @param _engine The SXCEngine contract to be tested
8284 /// @param _sxc The StableXCoin token contract
@@ -98,16 +100,105 @@ contract Handler is Test {
98100 /// @param collateralSeed Determines which token to use (WETH or WBTC)
99101 /// @param amountCollateral Amount of tokens to deposit
100102 function depositCollateral (uint256 collateralSeed , uint256 amountCollateral ) public {
101- ERC20Mock collateral = _getCollateralFromSeed (collateralSeed);
103+ ERC20Mock collateral = _getCollateralFromSeed (collateralSeed);
104+ uint256 clampedAmount = bound (amountCollateral, 1 , MAX_DEPOSIT_SIZE);
105+
106+ vm.startPrank (msg .sender );
107+ collateral.mint (msg .sender , clampedAmount);
108+ collateral.approve (address (engine), clampedAmount);
109+ engine.depositCollateral (address (collateral), clampedAmount);
110+ vm.stopPrank ();
111+ }
112+
113+
114+ /// @notice Attempts to mint StableXCoin (SXC) for the caller based on their collateral value
115+ /// @dev This function is used during fuzz testing to simulate minting. It ensures the user can only mint
116+ /// up to 50% of their collateral value in USD to maintain overcollateralization (e.g., 200% collateral ratio).
117+ /// If the user has already minted the maximum or has insufficient collateral, the function exits safely.
118+ /// @param amount The amount of StableXCoin (SXC) the user attempts to mint. This is bounded internally.
119+ /// @custom:invariant The function avoids minting if it would violate the collateralization ratio.
120+ function minSxc (uint256 amount ) public {
121+ // Clamp the initial amount to prevent unrealistic fuzzing input
122+ amount = bound (amount, 1 , MAX_DEPOSIT_SIZE);
123+
124+ // Get how much SXC the user has minted and how much collateral (in USD) they have deposited
125+ (uint256 totalSxcMinted , uint256 collateralValueInUsd ) = engine.getAccountInformation (msg .sender );
126+
127+ // Calculate the maximum amount of SXC the user is allowed to mint (200% collateralization ratio)
128+ int256 maxSxcToMint = (int256 (collateralValueInUsd) / 2 ) - int256 (totalSxcMinted);
129+
130+ // If the user is over their mint limit, exit safely
131+ if (maxSxcToMint < 0 ) {
132+ return ;
133+ }
102134
103- // Mint tokens to the caller so they can deposit
104- collateral. mint ( address ( this ), amountCollateral );
135+ // Clamp the mint amount to not exceed what they're allowed to mint
136+ amount = bound (amount, 0 , uint256 (maxSxcToMint) );
105137
106- // Approve and deposit to the engine
107- collateral. approve ( address (engine), amountCollateral);
108- engine. depositCollateral ( address (collateral), amountCollateral) ;
138+ // If the result is 0, skip the minting
139+ if (amount == 0 ) {
140+ return ;
109141 }
110142
143+ // Simulate a user calling mint on the engine
144+ vm.startPrank (msg .sender );
145+ engine.minSxc (amount);
146+ vm.stopPrank ();
147+ }
148+
149+
150+ // function depositCollateral(uint256 collateralSeed, uint256 amountCollateral) public {
151+ // ERC20Mock collateral = _getCollateralFromSeed(collateralSeed);
152+ // amountCollateral = bound(amountCollateral, 1, MAX_DEPOSIT_SIZE);
153+
154+ // // Mint tokens to the caller so they can deposit
155+ // collateral.mint(address(this), amountCollateral);
156+
157+ // // Approve and deposit to the engine
158+ // collateral.approve(address(engine), amountCollateral);
159+ // engine.depositCollateral(address(collateral), amountCollateral);
160+ // }
161+
162+ // function redeemCollateral(uint256 collateralSeed, uint256 amountCollateral){
163+ // ERC20Mock collateral = _getCollateralFromSeed(collateralSeed);
164+ // uint256 maxCollateralToRedeem = engine.getCollateralBalanceOfUser(address(collateral), msg.sender);
165+ // amountCollateral = bound(amountCollateral, 1, maxCollateralToRedeem);
166+ // if (amountCollateral == 0 ){
167+ // return;
168+ // }
169+ // engine.redeemCollateral(address(colateral), amountCollateral);
170+ // }
171+
172+
173+
174+ /// @notice Simulates redeeming collateral (WETH or WBTC) from the SXCEngine by the caller
175+ /// @dev Used during fuzz testing to simulate user withdrawals. The function ensures that the user
176+ /// only attempts to redeem an amount they have deposited (tracked by the engine).
177+ /// If the user has no redeemable balance or attempts to redeem zero, the function exits gracefully.
178+ /// @param collateralSeed Determines which collateral token to use (e.g., even = WETH, odd = WBTC)
179+ /// @param amountCollateral The amount of collateral to attempt to redeem. Bounded internally to a safe range.
180+ /// @custom:invariant The function avoids redeeming more than the user's tracked collateral balance in the engine.
181+ function redeemCollateral (uint256 collateralSeed , uint256 amountCollateral ) public {
182+ // Get WETH or WBTC based on the seed value
183+ ERC20Mock collateral = _getCollateralFromSeed (collateralSeed);
184+
185+ // Query the max amount of this token the user has in the engine
186+ uint256 maxCollateralToRedeem = engine.getCollateralBalanceOfUser (address (collateral), msg .sender );
187+
188+ // Clamp the amount to a valid, redeemable range
189+ uint256 clampedAmount = bound (amountCollateral, 1 , maxCollateralToRedeem);
190+
191+ // If they have nothing to redeem or fuzzed to 0, exit early
192+ if (clampedAmount == 0 ) return ;
193+
194+ // Simulate the user calling redeem
195+ vm.startPrank (msg .sender );
196+ engine.redeemCollateral (address (collateral), clampedAmount);
197+ vm.stopPrank ();
198+ }
199+
200+
201+
111202 // ========================
112203 // HELPERS
113204 // ========================
0 commit comments