Files
smom-dbis-138/test/security/Reentrancy.t.sol
2026-03-02 12:14:09 -08:00

109 lines
3.4 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../../contracts/bridge/UniversalCCIPBridge.sol";
import "../../contracts/liquidity/LiquidityManager.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
/**
* @title Reentrancy Security Tests
* @notice Tests for reentrancy protection
*/
contract ReentrancySecurityTest is Test {
UniversalCCIPBridge public bridge;
LiquidityManager public liquidityManager;
address public admin;
address public attacker;
function setUp() public {
admin = makeAddr("admin");
attacker = makeAddr("attacker");
vm.startPrank(admin);
UniversalCCIPBridge bridgeImpl = new UniversalCCIPBridge();
bytes memory bridgeInitData = abi.encodeWithSelector(
UniversalCCIPBridge.initialize.selector,
makeAddr("registry"),
makeAddr("router"),
admin
);
ERC1967Proxy bridgeProxy = new ERC1967Proxy(address(bridgeImpl), bridgeInitData);
bridge = UniversalCCIPBridge(payable(address(bridgeProxy)));
LiquidityManager lmImpl = new LiquidityManager();
bytes memory lmInitData = abi.encodeWithSelector(LiquidityManager.initialize.selector, admin);
ERC1967Proxy lmProxy = new ERC1967Proxy(address(lmImpl), lmInitData);
liquidityManager = LiquidityManager(address(lmProxy));
vm.stopPrank();
}
function testBridgeReentrancyProtection() public {
// Deploy malicious token that attempts reentrancy
MaliciousToken maliciousToken = new MaliciousToken(payable(address(bridge)));
vm.startPrank(attacker);
UniversalCCIPBridge.BridgeOperation memory op = UniversalCCIPBridge.BridgeOperation({
token: address(maliciousToken),
amount: 1000e18,
destinationChain: 1,
recipient: attacker,
assetType: bytes32(0),
usePMM: false,
useVault: false,
complianceProof: "",
vaultInstructions: ""
});
// Should fail due to reentrancy guard
vm.expectRevert();
bridge.bridge(op);
vm.stopPrank();
}
function testLiquidityManagerReentrancy() public {
// Test that liquidity manager has nonReentrant and returns safely for unconfigured token
vm.startPrank(attacker);
uint256 result = liquidityManager.provideLiquidity(makeAddr("token"), 1000e18, "");
assertEq(result, 0, "Unconfigured token should return 0");
vm.stopPrank();
}
}
/**
* @title MaliciousToken
* @notice Mock token that attempts reentrancy attack
*/
contract MaliciousToken {
address payable public bridge;
constructor(address payable _bridge) {
bridge = _bridge;
}
function transferFrom(address, address, uint256) external returns (bool) {
// Attempt reentrancy
UniversalCCIPBridge.BridgeOperation memory op = UniversalCCIPBridge.BridgeOperation({
token: address(this),
amount: 1000e18,
destinationChain: 1,
recipient: msg.sender,
assetType: bytes32(0),
usePMM: false,
useVault: false,
complianceProof: "",
vaultInstructions: ""
});
UniversalCCIPBridge(bridge).bridge(op);
return true;
}
}