22pragma solidity ^ 0.8.20 ;
33
44import {Test, console} from "forge-std/Test.sol " ;
5- import {Strategy, IWMEGA } from "../src/Strategy.sol " ;
5+ import {Strategy} from "../src/Strategy.sol " ;
66
7- // Mock WMEGA for this standalone test
8- contract MockWMEGALocal {
7+ // Mock MEGA ERC20 for this standalone test
8+ contract MockMEGALocal {
99 mapping (address => uint256 ) public balanceOf;
1010 mapping (address => mapping (address => uint256 )) public allowance;
11+ uint256 public totalSupply;
1112
12- function deposit () external payable {
13- balanceOf[msg .sender ] += msg .value ;
14- }
15-
16- function withdraw (uint256 amount ) external {
17- require (balanceOf[msg .sender ] >= amount, "Insufficient balance " );
18- balanceOf[msg .sender ] -= amount;
19- (bool success , ) = msg .sender .call {value: amount}("" );
20- require (success, "MEGA transfer failed " );
13+ function mint (address to , uint256 amount ) external {
14+ balanceOf[to] += amount;
15+ totalSupply += amount;
2116 }
2217
2318 function approve (address spender , uint256 amount ) external returns (bool ) {
@@ -49,15 +44,11 @@ contract MockWMEGALocal {
4944
5045 return true ;
5146 }
52-
53- receive () external payable {
54- balanceOf[msg .sender ] += msg .value ;
55- }
5647}
5748
5849contract StrategyAtomicityTest is Test {
5950 Strategy public giga;
60- MockWMEGALocal public wmega ;
51+ MockMEGALocal public mega ;
6152
6253 address public alice = address (0x1 );
6354 address public bob = address (0x2 );
@@ -78,40 +69,40 @@ contract StrategyAtomicityTest is Test {
7869 );
7970
8071 function setUp () public {
81- wmega = new MockWMEGALocal ();
82- giga = new Strategy (address (wmega ));
72+ mega = new MockMEGALocal ();
73+ giga = new Strategy (address (mega ));
8374
84- vm.deal (alice, 100 ether);
85- vm.deal (bob, 100 ether);
86- vm.deal (charlie, 100 ether);
75+ // Fund accounts with MEGA tokens
76+ mega.mint (alice, 100 ether);
77+ mega.mint (bob, 100 ether);
78+ mega.mint (charlie, 100 ether);
79+ }
80+
81+ // Helper to approve and mint
82+ function mintGiga (address user , uint256 amount ) internal {
83+ vm.startPrank (user);
84+ mega.approve (address (giga), amount);
85+ giga.mint (amount);
86+ vm.stopPrank ();
8787 }
8888
8989 function testFenwickTreeAtomicityDuringTransfers () public {
9090 // Setup: Create holders with exact amounts
91- vm.expectEmit (true , true , true , true );
92- emit Minted (alice, 10 ether, 9.9 ether, 0.1 ether);
93- vm.prank (alice);
94- giga.mint {value: 10 ether }();
91+ mintGiga (alice, 10 ether);
9592 assertEq (
9693 giga.balanceOf (alice),
9794 9.9 ether,
9895 "Alice should have 9,900 tokens "
9996 );
10097
101- vm.expectEmit (true , true , true , true );
102- emit Minted (bob, 5 ether, 4.95 ether, 0.05 ether);
103- vm.prank (bob);
104- giga.mint {value: 5 ether }();
98+ mintGiga (bob, 5 ether);
10599 assertEq (
106100 giga.balanceOf (bob),
107101 4.95 ether,
108102 "Bob should have 4,950 tokens "
109103 );
110104
111- vm.expectEmit (true , true , true , true );
112- emit Minted (charlie, 3 ether, 2.97 ether, 0.03 ether);
113- vm.prank (charlie);
114- giga.mint {value: 3 ether }();
105+ mintGiga (charlie, 3 ether);
115106 assertEq (
116107 giga.balanceOf (charlie),
117108 2.97 ether,
@@ -170,10 +161,7 @@ contract StrategyAtomicityTest is Test {
170161
171162 function testFenwickTreeAtomicityDuringMintAndBurn () public {
172163 // Initial mint
173- vm.expectEmit (true , true , true , true );
174- emit Minted (alice, 10 ether, 9.9 ether, 0.1 ether);
175- vm.prank (alice);
176- giga.mint {value: 10 ether }();
164+ mintGiga (alice, 10 ether);
177165 assertEq (
178166 giga.balanceOf (alice),
179167 9.9 ether,
@@ -216,22 +204,13 @@ contract StrategyAtomicityTest is Test {
216204 );
217205
218206 // Add another holder - mint slightly more to meet minimum requirement
219- // After minting period, there's a minimum mint of 100 wei
220- // 0.0001 MEGA will mint ~0.1 tokens (proportional to backing ratio)
221- // But actually after redemption backing changed, need to calculate properly
222- // Contract has ~9.901 MEGA, total supply is 9900 tokens
223- // To mint 100 wei: need (100 * 9.901) / 9900e18 = ~1e-16 MEGA
224- // But that's too small, let's mint 0.0001 MEGA to get a reasonable amount
225- uint256 mintNative = 0.0001 ether ;
226- uint256 expectedTokens = (mintNative * giga.totalSupply ()) /
227- address (giga).balance;
207+ uint256 mintAmount = 0.0001 ether ;
208+ uint256 expectedTokens = (mintAmount * giga.totalSupply ()) /
209+ giga.getMegaReserve ();
228210 uint256 expectedFee = expectedTokens / 100 ;
229211 uint256 expectedNet = expectedTokens - expectedFee;
230212
231- vm.expectEmit (true , true , true , true );
232- emit Minted (bob, mintNative, expectedNet, expectedFee);
233- vm.prank (bob);
234- giga.mint {value: mintNative}(); // Within capacity after redemption
213+ mintGiga (bob, mintAmount);
235214 assertEq (
236215 giga.balanceOf (bob),
237216 expectedNet,
@@ -253,9 +232,11 @@ contract StrategyAtomicityTest is Test {
253232 address [10 ] memory users;
254233 for (uint256 i = 0 ; i < 10 ; i++ ) {
255234 users[i] = address (uint160 (0x100 + i));
256- vm.deal (users[i], 10 ether);
257- vm.prank (users[i]);
258- giga.mint {value: 1 ether }();
235+ mega.mint (users[i], 10 ether);
236+ vm.startPrank (users[i]);
237+ mega.approve (address (giga), 1 ether);
238+ giga.mint (1 ether);
239+ vm.stopPrank ();
259240 }
260241
261242 // Verify initial state
@@ -300,12 +281,11 @@ contract StrategyAtomicityTest is Test {
300281 // the Fenwick tree remains consistent due to atomic updates
301282
302283 // Create a malicious contract that tries to reenter
303- MaliciousReentrant malicious = new MaliciousReentrant (giga);
304- vm. deal (address (malicious), 10 ether);
284+ MaliciousReentrant malicious = new MaliciousReentrant (giga, mega );
285+ mega. mint (address (malicious), 10 ether);
305286
306287 // Initial state
307- vm.prank (alice);
308- giga.mint {value: 10 ether }();
288+ mintGiga (alice, 10 ether);
309289
310290 uint256 initialFenwick = giga.getSuffixSum (1 );
311291 assertEq (
@@ -360,8 +340,7 @@ contract StrategyAtomicityTest is Test {
360340 // Test that Fenwick tree correctly handles accounts going to/from zero balance
361341
362342 // Alice mints
363- vm.prank (alice);
364- giga.mint {value: 1 ether }();
343+ mintGiga (alice, 1 ether);
365344
366345 uint256 aliceBalance = giga.balanceOf (alice);
367346 uint256 fenwick1 = giga.getSuffixSum (1 );
@@ -380,8 +359,7 @@ contract StrategyAtomicityTest is Test {
380359 );
381360
382361 // Alice mints again (goes from 0 to positive)
383- vm.prank (alice);
384- giga.mint {value: 2 ether }();
362+ mintGiga (alice, 2 ether);
385363
386364 // Both should be tracked now
387365 uint256 fenwick3 = giga.getSuffixSum (1 );
@@ -393,18 +371,21 @@ contract StrategyAtomicityTest is Test {
393371// Helper contract for reentrancy test
394372contract MaliciousReentrant {
395373 Strategy public giga;
374+ MockMEGALocal public mega;
396375 bool public attacked = false ;
397376
398- constructor (Strategy _giga ) {
377+ constructor (Strategy _giga , MockMEGALocal _mega ) {
399378 giga = _giga;
379+ mega = _mega;
400380 }
401381
402382 // Try to reenter when receiving tokens
403383 function onERC20Received (address , uint256 ) external returns (bytes4 ) {
404384 if (! attacked) {
405385 attacked = true ;
406386 // Try to mint during a transfer (should fail due to reentrancy guard)
407- try giga.mint {value: 1 ether }() {
387+ mega.approve (address (giga), 1 ether);
388+ try giga.mint (1 ether) {
408389 // Should not reach here
409390 } catch {
410391 // Expected to fail
0 commit comments