Skip to content

Commit 73d3903

Browse files
authored
Add full test coverage (#1)
1 parent f42adbb commit 73d3903

File tree

3 files changed

+135
-4
lines changed

3 files changed

+135
-4
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
forge build --sizes
3535
id: build
3636

37-
# - name: Run Forge tests
38-
# run: |
39-
# forge test -vvv
40-
# id: test
37+
- name: Run Forge tests
38+
run: |
39+
forge test -vvv
40+
id: test

test/.gitkeep

Whitespace-only changes.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol";
5+
import {IERC20} from "forge-std/interfaces/IERC20.sol";
6+
import {Test} from "forge-std/Test.sol";
7+
8+
import {ForwardingAddress} from "../src/ForwardingAddress.sol";
9+
import {ForwardingAddressFactory} from "../src/ForwardingAddressFactory.sol";
10+
11+
contract NonPayableReceiver {}
12+
13+
contract ForwardingAddressFactoryTest is Test {
14+
ForwardingAddressFactory public factory;
15+
ERC20Mock public erc20Mock;
16+
17+
function setUp() public {
18+
factory = new ForwardingAddressFactory();
19+
erc20Mock = new ERC20Mock();
20+
}
21+
22+
function testFuzz_createForwardingAddress(bytes32 salt) public {
23+
(address receiver,) = makeAddrAndKey("receiver");
24+
25+
address expectedAddr = factory.getAddress(receiver, salt);
26+
address actualAddress = address(factory.createForwardingAddress(payable(receiver), salt));
27+
28+
assertEq(expectedAddr, actualAddress);
29+
assertEq(ForwardingAddress(payable(actualAddress)).receiver(), receiver);
30+
}
31+
32+
function testFuzz_createForwardingAddressAlreadyDeployed(bytes32 salt) public {
33+
(address receiver,) = makeAddrAndKey("receiver");
34+
35+
address expectedAddr = factory.getAddress(receiver, salt);
36+
factory.createForwardingAddress(payable(receiver), salt);
37+
address actualAddress = address(factory.createForwardingAddress(payable(receiver), salt));
38+
39+
assertEq(expectedAddr, actualAddress);
40+
}
41+
42+
function testFuzz_saltUniqueness(bytes32 salt1, bytes32 salt2) public {
43+
vm.assume(salt1 != salt2);
44+
(address receiver,) = makeAddrAndKey("receiver");
45+
46+
ForwardingAddress f1 = factory.createForwardingAddress(payable(receiver), salt1);
47+
ForwardingAddress f2 = factory.createForwardingAddress(payable(receiver), salt2);
48+
49+
assertNotEq(address(f1), address(f2));
50+
assertEq(f1.receiver(), f2.receiver());
51+
}
52+
53+
function testFuzz_receiverUniqueness(bytes32 salt) public {
54+
(address r1,) = makeAddrAndKey("r1");
55+
(address r2,) = makeAddrAndKey("r2");
56+
vm.assume(r1 != r2);
57+
58+
ForwardingAddress f1 = factory.createForwardingAddress(payable(r1), salt);
59+
ForwardingAddress f2 = factory.createForwardingAddress(payable(r2), salt);
60+
61+
assertNotEq(address(f1), address(f2));
62+
assertNotEq(f1.receiver(), f2.receiver());
63+
}
64+
65+
function testFuzz_sweepForETH(bytes32 salt, uint256 amount) public {
66+
(address receiver,) = makeAddrAndKey("receiver");
67+
68+
address forwarder = factory.getAddress(receiver, salt);
69+
vm.deal(forwarder, amount);
70+
assertEq(receiver.balance, 0);
71+
assertEq(forwarder.balance, amount);
72+
73+
address[] memory tokens = new address[](1);
74+
tokens[0] = address(0);
75+
factory.sweepFor(payable(receiver), salt, tokens);
76+
assertEq(receiver.balance, amount);
77+
assertEq(forwarder.balance, 0);
78+
}
79+
80+
function testFuzz_sweepForFailedETHWithdraw(bytes32 salt, uint256 amount) public {
81+
address receiver = address(new NonPayableReceiver());
82+
83+
address forwarder = factory.getAddress(receiver, salt);
84+
vm.deal(forwarder, amount);
85+
assertEq(receiver.balance, 0);
86+
assertEq(forwarder.balance, amount);
87+
88+
address[] memory tokens = new address[](1);
89+
tokens[0] = address(0);
90+
vm.expectRevert(abi.encodeWithSelector(ForwardingAddress.FailedETHWithdraw.selector, receiver, tokens[0]));
91+
factory.sweepFor(payable(receiver), salt, tokens);
92+
assertEq(receiver.balance, 0);
93+
assertEq(forwarder.balance, amount);
94+
}
95+
96+
function testFuzz_sweepForERC20(bytes32 salt, uint256 amount) public {
97+
(address receiver,) = makeAddrAndKey("receiver");
98+
99+
address forwarder = factory.getAddress(receiver, salt);
100+
erc20Mock.mint(forwarder, amount);
101+
assertEq(IERC20(address(erc20Mock)).balanceOf(receiver), 0);
102+
assertEq(IERC20(address(erc20Mock)).balanceOf(forwarder), amount);
103+
104+
address[] memory tokens = new address[](1);
105+
tokens[0] = address(erc20Mock);
106+
factory.sweepFor(payable(receiver), salt, tokens);
107+
assertEq(IERC20(address(erc20Mock)).balanceOf(receiver), amount);
108+
assertEq(IERC20(address(erc20Mock)).balanceOf(forwarder), 0);
109+
}
110+
111+
function testFuzz_sweepForMulti(bytes32 salt, uint256 amount) public {
112+
(address receiver,) = makeAddrAndKey("receiver");
113+
114+
address forwarder = factory.getAddress(receiver, salt);
115+
vm.deal(forwarder, amount);
116+
erc20Mock.mint(forwarder, amount);
117+
assertEq(receiver.balance, 0);
118+
assertEq(forwarder.balance, amount);
119+
assertEq(IERC20(address(erc20Mock)).balanceOf(receiver), 0);
120+
assertEq(IERC20(address(erc20Mock)).balanceOf(forwarder), amount);
121+
122+
address[] memory tokens = new address[](2);
123+
tokens[0] = address(0);
124+
tokens[1] = address(erc20Mock);
125+
factory.sweepFor(payable(receiver), salt, tokens);
126+
assertEq(receiver.balance, amount);
127+
assertEq(forwarder.balance, 0);
128+
assertEq(IERC20(address(erc20Mock)).balanceOf(receiver), amount);
129+
assertEq(IERC20(address(erc20Mock)).balanceOf(forwarder), 0);
130+
}
131+
}

0 commit comments

Comments
 (0)