Skip to content

Commit 9ca4c21

Browse files
feat: Add negative tests for PayNodeRouter covering low amounts, zero addresses, and unauthorized payWithPermit callers, and refine orderId generation in fuzz tests.
1 parent abe952c commit 9ca4c21

1 file changed

Lines changed: 57 additions & 2 deletions

File tree

test/PayNodeRouter.t.sol

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ contract PayNodeRouterTest is Test {
127127

128128
usdc.mint(payer, amount);
129129

130-
bytes32 orderId = keccak256("fuzz_order");
130+
bytes32 orderId = keccak256(abi.encodePacked("fuzz_order", amount, fuzzMerchant));
131131

132132
uint256 payerBalanceBefore = usdc.balanceOf(payer);
133133
uint256 merchantBalanceBefore = usdc.balanceOf(fuzzMerchant);
@@ -154,7 +154,7 @@ contract PayNodeRouterTest is Test {
154154
// Mint extra to ensure enough balance for high fuzz amounts
155155
usdc.mint(payer, amount);
156156

157-
bytes32 orderId = keccak256("fuzz_order_permit");
157+
bytes32 orderId = keccak256(abi.encodePacked("fuzz_order_permit", amount, fuzzMerchant));
158158
uint256 deadline = block.timestamp + 1 hours;
159159

160160
bytes32 permitTypehash =
@@ -172,4 +172,59 @@ contract PayNodeRouterTest is Test {
172172

173173
assertEq(usdc.balanceOf(treasury), treasuryBalanceBefore + (amount / 100));
174174
}
175+
176+
// --- Negative Tests ---
177+
178+
function test_RevertWhen_AmountTooLow() public {
179+
uint256 tooLow = 999; // Below MIN_PAYMENT_AMOUNT (1000)
180+
bytes32 orderId = keccak256("order_dust");
181+
182+
vm.prank(payer);
183+
usdc.approve(address(router), tooLow);
184+
185+
vm.expectRevert(PayNodeRouter.AmountTooLow.selector);
186+
vm.prank(payer);
187+
router.pay(address(usdc), merchant, tooLow, orderId);
188+
}
189+
190+
function test_RevertWhen_MerchantIsZeroAddress() public {
191+
uint256 amount = 100 * 10 ** 6;
192+
bytes32 orderId = keccak256("order_zero_merchant");
193+
194+
vm.prank(payer);
195+
usdc.approve(address(router), amount);
196+
197+
vm.expectRevert(PayNodeRouter.InvalidAddress.selector);
198+
vm.prank(payer);
199+
router.pay(address(usdc), address(0), amount, orderId);
200+
}
201+
202+
function test_RevertWhen_TokenIsZeroAddress() public {
203+
uint256 amount = 100 * 10 ** 6;
204+
bytes32 orderId = keccak256("order_zero_token");
205+
206+
vm.expectRevert(PayNodeRouter.InvalidAddress.selector);
207+
vm.prank(payer);
208+
router.pay(address(0), merchant, amount, orderId);
209+
}
210+
211+
function test_RevertWhen_PayWithPermit_CallerIsNotPayer() public {
212+
uint256 amount = 100 * 10 ** 6;
213+
bytes32 orderId = keccak256("order_unauthorized");
214+
uint256 deadline = block.timestamp + 1 hours;
215+
216+
bytes32 permitTypehash =
217+
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
218+
bytes32 structHash =
219+
keccak256(abi.encode(permitTypehash, payer, address(router), amount, usdc.nonces(payer), deadline));
220+
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", usdc.DOMAIN_SEPARATOR(), structHash));
221+
222+
(uint8 v, bytes32 r, bytes32 s) = vm.sign(payerPrivateKey, digest);
223+
224+
// Call from a different address (not payer)
225+
address attacker = address(0xBEEF);
226+
vm.expectRevert(PayNodeRouter.UnauthorizedCaller.selector);
227+
vm.prank(attacker);
228+
router.payWithPermit(payer, address(usdc), merchant, amount, orderId, deadline, v, r, s);
229+
}
175230
}

0 commit comments

Comments
 (0)