DatingDapp

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

matchRewards() deploys MultiSigWallet but never stores or emits the address, making matched users' reward wallet undiscoverable on-chain

Root + Impact

Description

  • When two users match, matchRewards() deploys a new MultiSigWallet and sends reward ETH to it. The address of that wallet is the only way the two matched users can interact with their funds.

  • The deployed address is assigned to a local variable multiSigWallet but is never stored in any mapping and no event is emitted containing it. Users have no on-chain mechanism to look up which MultiSig belongs to their match.

// src/LikeRegistry.sol — matchRewards()
function matchRewards(address from, address to) internal {
...
// @> address only in local variable — never stored, never emitted
MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);
(bool success,) = payable(address(multiSigWallet)).call{value: rewards}("");
require(success, "Transfer failed");
// @> function ends — multiSigWallet address is gone
}

The existing Matched event is emitted in likeUser before matchRewards is called and contains only the two user addresses — not the wallet address.

Risk

Likelihood:

  • Every match deployment loses its wallet address. Every matched pair is affected.

Impact:

  • Matched users must scan historical transaction data off-chain to find their MultiSig. Wallets without a frontend index (block explorer, dedicated subgraph) cannot surface the address to users at all, effectively hiding their funds.

Proof of Concept

A static grep of the source confirms the issue. Matched is emitted before matchRewards is called, so the event carries no wallet address. Inside matchRewards, the deployed wallet address is stored only in a local variable that goes out of scope when the function returns.

grep -n "emit\|multiSigWallet\|matches\[" src/LikeRegistry.sol
24: event Liked(address indexed liker, address indexed liked);
25: event Matched(address indexed user1, address indexed user2);
44: emit Matched(msg.sender, liked);
45: matchRewards(liked, msg.sender);
62: MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);

Matched is emitted on line 44, before matchRewards runs on line 45. The wallet is deployed inside matchRewards on line 62 with no subsequent event emission. Users listening for Matched receive no wallet address.

Recommended Mitigation

Store the deployed wallet address in a mapping and extend the Matched event to include it:

+ mapping(address => mapping(address => address)) public matchToWallet;
- event Matched(address indexed user1, address indexed user2);
+ event Matched(address indexed user1, address indexed user2, address wallet);
function matchRewards(address from, address to) internal {
...
MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);
+ matchToWallet[from][to] = address(multiSigWallet);
+ matchToWallet[to][from] = address(multiSigWallet);
+ emit Matched(from, to, address(multiSigWallet));
(bool success,) = payable(address(multiSigWallet)).call{value: rewards}("");
require(success, "Transfer failed");
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 4 hours 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!