Open hats-bug-reporter[bot] opened 2 months ago
For an appeal to be created, both sides should be funded. If only one side is funded, this side will be considered the winning side irrespective of the ruling.
In your example everything you describes works as intended, if no one takes a side different than Bob, his side will win.
If Carl funds a side opposing to Bob, un the subsequent fundAppeal
we will have firstFunded
be Bob and the condition to create an appeal will be satisfied.
Github username: -- Twitter username: -- Submission hash (on-chain): 0xd13ab2125a9338b7e96796da5b13a9c76b6f5ac10f527d34b23cc7228ba51121 Severity: high
Description: Description:
When a user challenges a claim using the
challengeRequest
function, a new round is created for therequest.challenges[challengeId]
variable:Since this is a new round, it has no pre-existing data and is primarily used to store appeal deposits.
When a user calls the
fundAppeal
function with a specificside
and provides sufficientmsg.value
to fund an appeal, a local variablefirstFunded
is created:In this context, the
firstFunded
variable is initially set toParty.None
because the round being referenced in thefundAppeal
function is a new round. By default, a new round'ssideFunded
variable has the valueParty.None
.This variable is subsequently checked against
Party.None
after thefundAppeal
function invokes the_contribute
function to handle contributions and update the round:However,
firstFunded
is a local variable created within thefundAppeal
function and its value is set before the_contribute
function is called. As a result, it does not get updated during the execution of_contribute
.Therefore, when the
firstFunded
variable is compared toParty.None
, the conditionfirstFunded != Party.None
will always evaluate to false. Consequently, an appeal will not be created.This issue prevents appeals from ever being initiated, which means that challenges cannot be contested further, effectively breaking a core functionality of the protocol — the appeals system.
The
_contribute
function is executed during the check of the aboveif
condition. As explained earlier, the code within theif
statement will never execute. This leads to a scenario where, if a user provides sufficient funds when calling thefundAppeal
function, the_contribute
function sets the current round'ssideFunded
variable according to the side chosen by the caller:Due to the aforementioned reasons, the
if
condition inside thefundAppeal
function will not execute, and thus the current round does not advance to a new one:As a result, the current round's
sideFunded
value is set based on the caller's choice in thefundAppeal
function.Later, when the
rule
function is called and executed, since the round is not updated as mentioned, the winner of the dispute will always be determined by the side chosen by the caller offundAppeal
:This flaw allows any malicious user to front-run the
rule
function by calling thefundAppeal
function with their desired winner, effectively allowing them to determine the outcome of the dispute regardless of the arbitrator's actual ruling, thereby bypassing the challenge system.Scenario:
challengeRequest
function, which creates a new round by incrementingchallenge.lastRoundId
. This new round has no data, serving primarily to hold appeal deposits.fundAppeal
function with sufficientmsg.value
to make an appeal. Inside this function, a local variablefirstFunded
is initialized toround.sideFunded
. Since this is a new round,round.sideFunded
is set toParty.None
by default. Thus,firstFunded
is initialized toParty.None
.fundAppeal
function calls the_contribute
function to update the round and contribute to the appeal. ThefirstFunded
variable is checked after the_contribute
call to see if it differs fromParty.None
. However, sincefirstFunded
is a local variable and not updated by_contribute
, it retains its initial value (Party.None
). Thus, the conditionfirstFunded != Party.None
always evaluates tofalse
, preventing the appeal from being created.fundAppeal
, theround.sideFunded
is updated based on the caller’s chosen side (eitherParty.Requester
orParty.Challenger
).rule
function is called to finalize the dispute, the winner is determined based on theround.sideFunded
value.Solution:
Convert
firstFunded
to a State Variable.