DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

MEDIUM-01 — DoS risk from deploying MultiSigWallet on every match

MEDIUM-01 — DoS risk from deploying MultiSigWallet on every match

Description

  • Every match triggers a new MultiSigWallet(from, to) deployment inline within likeUser. Deploying a contract is one of the most gas-expensive operations in the EVM. If the gas cost exceeds the block gas limit or the caller doesn't supply enough gas, the entire likeUser transaction reverts, permanently preventing those two users from ever matching.

function matchRewards(address from, address to) internal {
// @> contract deployment on every match - high gas cost
MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);
(bool success,) = payable(address(multiSigWallet)).call{value: rewards}("");
require(success, "Transfer failed");
}

Risk

Likelihood:

  • Triggered on every match. Risk increases during network congestion or if called from contracts with limited gas forwarding.

Impact:

  • Matched users cannot receive their rewards. ETH remains locked in LikeRegistry. The match is recorded in state but funds are unclaimable.

Proof of Concept

function test_matchRevertsIfNotEnoughGas() public {
// Setup - both users have profiles
vm.prank(alice);
profileNFT.mintProfile("Alice", 25, "ipfs://alice");
vm.prank(bob);
profileNFT.mintProfile("Bob", 26, "ipfs://bob");
// Alice likes Bob
vm.prank(alice);
registry.likeUser{value: 1 ether}(bob);
// Bob likes Alice - triggers matchRewards internally
// matchRewards deploys a new MultiSigWallet (~500k gas)
// If called from a contract with limited gas forwarding
// or during network congestion - entire transaction reverts
vm.prank(bob);
vm.expectRevert();
registry.likeUser{value: 1 ether, gas: 100000}(alice);
// Result: Alice and Bob can never be matched
assertEq(registry.matches(alice).length, 0);
}

Recommended Mitigation

- MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);
- (bool success,) = payable(address(multiSigWallet)).call{value: rewards}("");
- require(success, "Transfer failed");
// Use pull pattern instead
+ userBalances[from] += rewards / 2;
+ userBalances[to] += rewards / 2;
+ function withdraw() external {
+ uint256 amount = userBalances[msg.sender];
+ require(amount > 0, "Nothing to withdraw");
+ userBalances[msg.sender] = 0;
+ (bool success,) = payable(msg.sender).call{value: amount}("");
+ require(success, "Transfer failed");
+ }
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 8 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!