When a mutual like occurs, the contract deploys a new MultiSigWallet instance inside matchRewards and transfers ETH rewards to it:
However, the address of the deployed multisig wallet is neither stored in contract state nor emitted in any event.
The matches mapping only records counterpart user addresses:
As a result, matched users have no on-chain method to discover the multisig wallet that holds their rewards.
Users must manually inspect transaction traces or rely on off-chain indexing to locate the deployed multisig address, which introduces friction and reduces composability with other smart contracts or automation systems.
Impact: Low
No funds are lost and the rewards are correctly sent to the deployed multisig wallet. However, users cannot programmatically retrieve the multisig address associated with a match, making it difficult to access or manage their rewards and preventing trustless integration with other on-chain systems.
Likelihood: High
This behavior occurs for every successful match, since a multisig wallet is deployed on each match and its address is never persisted or emitted. All matched users will encounter this limitation.
User A and User B both hold valid profile NFTs.
User A likes User B by calling likeUser(UserB) and sending the required ETH.
Since the like is not mutual yet, no match is created and no multisig wallet is deployed.
User B later likes User A by calling likeUser(UserA) and sending the required ETH.
This time, the mutual-like condition is met and:
A new multisig wallet is deployed internally.
ETH rewards are transferred to the deployed multisig wallet.
The Matched event is emitted.
Both users are added to each other’s matches list.
After the match, User A or User B attempts to determine the multisig wallet address that holds their rewards.
They can:
Call getMatches() to retrieve matched counterpart addresses.
Inspect emitted Matched events.
=> Neither getMatches() nor any event provides the multisig wallet address.
The contract also does not store the multisig address in state.
=> As a result, the users have no on-chain or in-contract method to retrieve the multisig wallet address associated with their match.
=> The only way to find it is by manually inspecting transaction traces or using off-chain tooling to infer the deployment address.
Put this following mitigation in contract LikeRegistry:
Introduce a new MatchInfo struct to store match metadata, including the matched user and the associated multisig contract address.
Change the matches mapping from address => address[] to address => MatchInfo[] to persist multisig information on-chain.
Include the multisig contract address as a parameter in the Matched event.
Update match data is stored inside the matchReward function instead.
Emit the Matched event from the matchRewards function after the multisig wallet is deployed, ensuring the emitted address reflects the actual deployed contract.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.