Normal behavior: liking is a bet on a mutual match. A user who likes one or more people but never matches should be able to recover the ETH they staked, and a user should never lose more than the amount they intended to stake per like. In a healthy design there is an unlike/refund for pending likes and the like amount is exact (or the surplus is returned).
Specific issue: LikeRegistry has NO exit path for a liker's funds outside of a successful mutual match. There is no unlike, no refund, and no per-user withdraw function anywhere in the contract; the only ETH-out functions are matchRewards (internal, only on a mutual match) and withdrawFees (owner, only the accrued fees). This creates three distinct, permanent losses, none of which is fixed by simply adding the missing credit from finding #1:
Never-matched stake is stuck. A user likes someone who never likes them back. Their >= 1 ETH sits in the contract with no way to reclaim it. Since most likes on a dating app never become mutual, this is the common case, not an edge case.
Liked user disappears. If the liked user burns their profile (or is blocked by the owner) before reciprocating, the mutual match can never occur, so the liker's stake is locked forever with certainty.
Overpayment is lost outright. likeUser only enforces a >= 1 ether FLOOR — there is no cap and no refund of the surplus. A user who sends 2 ETH (or fat-fingers 50 ETH) for a single like loses everything above the intended stake, because the excess is never tracked or returned.
The natural user workaround — burn the profile and re-mint to "reset" — does not free the funds either, and is additionally blocked from re-liking by the stale-state issue in finding #3. So once ETH enters likeUser, the only way it ever leaves is a mutual match; every other path is a permanent loss.
Likelihood:
The majority of likes never become mutual matches, so unrecoverable stakes are the norm, not an edge case.
The liked user burning/being-blocked before reciprocating is a normal lifecycle event.
Overpaying (or sending a round number > 1 ETH) is an easy and irreversible user mistake.
Impact:
Permanent loss of every stake that does not result in a match (the common outcome), permanent loss when a counterparty leaves before matching, and total loss of any amount sent above 1 ETH per like. Because there is no withdraw path at all, these funds are irrecoverable by the user, the counterparty, or even the owner.
test/LikeRegistryAudit.t.sol::testExcessValueLockedNoRefund (PASS): Alice sends 50 ETH in one likeUser call and loses all 50 (userBalances(alice)==0, registry.balance==50 ETH). test/SeamAudit.t.sol::test_F3_likedUserBurns_likerEthStuckNoRecovery (PASS): the liked user burns their profile; the liker's 1 ETH is stuck with no recovery.
Add an unlike/refund for pending (un-matched) likes and a per-user withdraw; refund msg.value above the required stake, or require exactly the stake amount.
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.