Trueo engaged Guardian to review the security of their decentralized prediction market platform, enabling users to forecast outcomes of real world events. From the 13th of January to the 27th of January, a team of 6 auditors reviewed the source code in scope.
- Published
- Review window
- January 13 to 27, 2025
- Language
- Solidity
- Chains
- Base
- Sector
- Derivatives
- 1 Critical
- 6 High
- 13 Medium
- 19 Low
- 0 Informational
Scope
Overview
Trueo engaged Guardian to review the security of their decentralized prediction market platform, enabling users to forecast outcomes of real world events. From the 13th of January to the 27th of January, a team of 6 auditors reviewed the source code in scope.
Issues Detected Throughout the engagement 7 High/Critical issues were uncovered and promptly remediated by the Trueo team.
Security Recommendation Given the number of High and Critical issues detected as well as additional code changes made after the main review, Guardian recommends that an independent security review of the protocol at a finalized frozen commit is conducted before deployment.
Findings 39
-
C-01 Critical New Resolver Loses Bond After Council Reset Logical Error Resolved
Description
Proof of concept: PoC
In the sendResolverBondToMarket function, the resolver bond is currently stored using:
marketBond[_market].resolverBond = _amount;This approach overwrites any existing resolver bond, which is generally acceptable as only one resolution is expected.
However, an issue arises when a market status is
resetByCouncil. Here’s the problematic sequence: 1. Reset State: The council votes to reset the market, leaving the previous resolver's bond intact but not immediately returned. 2. New Proposal: A new resolver proposes a resolution, adding their bond via sendResolverBondToMarket. 3. Bond Overwrite: The resolverBond value is overwritten with the new bond, effectively discarding the previous bond value. 4. Loss of Funds: When the previous bond is sent to the disputor (to punish original resolver), the resolverBond is reset to zero, causing the new resolver to lose their bond.Recommendation
To handle the situation where multiple bonds coexist during a reset, the resolver bonds should be stored incrementally and decremented appropriately when withdrawn or refunded.
Modify
sendResolverBondToMarketto increment the value by the new bond amount:marketBond[_market].resolverBond = _amount.Similarly, in
sendBondFromMarketToSafeBoxandissueBondsBackToResolver, decrement the resolver bond by the transferred amount instead of setting it to zero.Resolution
Trueo Team: Resolved.
-
H-01 High Second Challenge Period Can Be Bypassed Logical Error Acknowledged
Description
Proof of concept: PoC
When the market is in the
MarketStatus.ResetByCouncilstate, it should wait for thesecondChallengePeriodbefore opening for resolution to allowopenEscalatedDispute. However,proposeResolutioncan be called immediately without waiting for thesecondChallengePeriod.The bypass of
secondChallengePeriodallows a dishonest disputor to move the market status toResolutionProposedtherefore earning the resolver's bond before the resolver has a chance to escalate the issue.Recommendation
Consider moving
_updateStatusexecution before settingcouncilDecisionAt = 0.Resolution
Trueo Team: Acknowledged.
-
H-02 High Resolver Might Not Receive The Deserved Reward Logical Error Resolved
Description
When a market is finalized and ends with
_CANCELEDas thewinningPosition, users can triggerwithdrawFromCanceledMarketto withdraw their payment tokens.Within
withdrawFromCanceledMarket, ifbondSettledis not yet settled, it will trigger_settleBondsto handle reward payments and bond refunds or slashes.However, if the market previously entered a dispute or escalation state, it will transfer the reward to the
safeBoxAddresswhen thewinningPositionis_CANCELED, regardless of whether theoriginalOutcomeFromResolveris equal to_CANCELED.This will result in the resolver not receiving the deserved reward.
Recommendation
Only transfer reward to
safeBoxAddresswhenwinningPositionis_CANCELEDandwinningPositionis not equal tooriginalOutcomeFromResolverResolution
Trueo Team: Resolved.
-
H-03 High Old Disputes Can Be Reused After ResetByCouncil Logical Error Resolved
Description
Proof of concept: PoC
When a market is partially disputed, multiple disputes can be opened in parallel. If one of those disputes concludes first (e.g., triggering a
ResetByCouncil), the market transitions back toOpenForResolution, and any unclosed disputes remain in storage, still carrying prior votes.Because those old disputes are never marked as permanently invalid, they can be reused when the market enters a new resolution flow—allowing a malicious council member to “revive” the partially-voted dispute and finalize it with minimal new votes.
In the provided example:
- A market transitions to
ResolutionProposedwith a “YES” outcome. - Two different disputers each open a separate dispute (Dispute #1 and Dispute #2).
- Dispute #1 closes first (for example, by a majority that sets
ResetByCouncil), while Dispute #2 remains open but unresolvable at that moment due to the market status update. - The market then resets, returning to
OpenForResolution(or evenResolutionProposedagain). - A malicious council member can propose a new outcome, open a fresh dispute, but then re-invoke the old, unresolved Dispute #2. Because that older dispute already has partial votes recorded, the malicious user can cast a single new vote (or minimal votes) to reach a majority, effectively closing Dispute #2 and imposing its outcome—even though other council members haven’t re-voted under the new context.
Recommendation
Invalidate or close all existing disputes when the market transitions from
SetByCouncilorResetByCouncilback toOpenForResolution.Resolution
Trueo Team: Resolved.
Guardian Team: The new check
if (_disputeIndex <= marketLastClosedDispute[_market]) revertDisputeInvalid();is ineffective because an old dispute may have a higher index than the last closed dispute. 15 - A market transitions to
-
H-04 High Unrestricted burn Could Lead To Unsettled Bonds Logical Error Resolved
Description
burncan be called by anyone at any market state, allowing users to burn their yes and no tokens to retrieve the deposit tokens.This could cause issues in a scenario where the market is finalized, especially when the winning position is
_CANCELED. Instead of callingwithdrawFromCanceledMarket, users might choose to callburnto reclaim their deposit tokens.This would prevent
_settleBondsfrom being triggered, causing all bonds and rewards to remain stuck and unresolved.Recommendation
Consider restricting
burnso it can only be called when the market is not finalized. Additionally, make settle bonds publicly callable in cases where no token holders decide to redeem or withdraw their tokens.Resolution
Trueo Team: Resolved.
-
H-05 High Locked Dispute Bonds After Escalation Reset DOS Resolved
Description
Proof of concept: PoC
When a dispute is resolved by the council and its escalation leads to a Reset result, any user with an “unclosed dispute” bond remains unable to claim it because
reopenMarketForDisputessetsmarketClosedForDisputesto false.Consequently, once the market transitions to a new proposal, if it finalizes with no disputes, the dispute is never recognized as “closed” or “canceled,” preventing
claimUnclosedDisputeBondsfrom succeeding. The disputer’s bond remains locked, and they are unable to recover their funds.Recommendation
Update
canDisputorClaimbackBondFromUnclosedDisputeto allow bond retrieval if the market has been reset, rather than strictly requiring it to be “closed for disputes” or “finalized.” This ensures no user is stuck with an unclaimable dispute bond after the escalation reset.Resolution
Trueo Team: Resolved.
-
H-06 High Token Holder Vote Cannot Be Disputed Logical Error Acknowledged
Description
The current implementation dictates that once an escalation is decided by a token holders' vote, the market either resolves to Finalized or reverts to
OpenForResolution, with no mechanism to dispute this decision.However, according to the documentation, a third challenge window should exist, enabling any holder of 250,000 TRUE tokens to dispute the escalation result and escalate the matter to the Attesters.
The absence of this challenge window introduces a vulnerability where large TRUE token holders could manipulate the vote for financial gain, leaving other stakeholders without any recourse to contest the outcome.
Recommendation
Introduce a third challenge window as outlined in the documentation, ensuring that escalation decisions can be disputed and reviewed by the Attesters.
Resolution
Trueo Team: Acknowledged.
-
M-01 Medium NoToken Cap May Be Exceeded During Minting Logical Error Resolved
Description
The mint function enforces the
yesNoTokenCap, but it only checks the supply of Yes tokens. This creates a potential issue where the supply of No tokens can exceed the cap if there is an imbalance between the total supply of Yes and No tokens.This imbalance can occur because Yes tokens can be burned (since
YesNoTokenis anERC20Burnablecontract).For example:
yesNoTokenCap= 100- Initial supply: Yes = 90, No = 90
- A user burns 10 Yes tokens, reducing the Yes supply to 80.
- The same user mints 20 Yes tokens, bringing the Yes supply back to 100.
- The final supply becomes: Yes = 100, No = 110, exceeding the cap.
Recommendation
Check that the No token supply does not exceed the
yesNoTokenCapduring minting.Resolution
Trueo Team: Resolved.
-
M-02 Medium Council Members Cannot Set Challenge Period Access Control Resolved
Description
Inside
TruthMarketManagerV2, several functions are available to manage the market's configuration that can be called by the oracle council, such assetYesNoTokenCap,setEndOfTrading,setFirstChallengePeriod, andsetSecondChallengePeriod.While
setYesNoTokenCapandsetEndOfTradingare currently available in theOracleCouncilV2contract,setFirstChallengePeriodandsetSecondChallengePeriodare not implemented, preventing council members from configuring those market settings.Recommendation
Implement
setFirstChallengePeriodandsetSecondChallengePeriodinsideOracleCouncilV2.Resolution
Trueo Team: Resolved.
-
M-03 Medium Possible DOS In _getTotalOpenDisputes DOS Acknowledged
Description
The
_getTotalOpenDisputesfunction is used by theaddOracleCouncilMemberandremoveOracleCouncilMemberfunctions in theOracleCouncilcontract.This function calculates the total open disputes by looping through all active markets and checking if each market is in the
DisputeRaisedstatus and has any open disputes. The issue is that _activeMarkets does not have a cap, meaning it could grow indefinitely.As a result, the gas costs for calling
_getTotalOpenDisputescan become excessively high, potentially exceeding the block gas limit and causing the transaction to fail.This could effectively lock the
addOracleCouncilMemberandremoveOracleCouncilMemberfunctions, preventing them from being executed.Recommendation
Introduce a cap on the size of
_activeMarketsor consider optimizing the function to avoid iterating through markets that are in a finalized state, as they cannot return to the disputed state.Resolution
Trueo Team: Acknowledged.
-
M-04 Medium Owner Cannot Trigger disputeMarket Access Control Resolved
Description
Many operations inside
TruthMarketManagerV2that change the market state can be manually triggered by the owner. This is needed in cases where markets are paused, as only the owner can initiate market state transitions, includingdisputeMarket.However,
disputeMarketuses theonlyOracleCouncilmodifier, which restricts the function to being called only by the oracle council. This is despite the function logic including a check allowing the owner to triggerdisputeMarketwhen markets are paused.As a result,
disputeMarketcannot be manually called by the owner when markets are paused.Recommendation
Consider to use
onlyOracleCouncilAndOwnerinstead.Resolution
Trueo Team: Resolved.
-
M-05 Medium Inefficient Distribution In StakingRewards Logical Error Acknowledged
Description
Proof of concept: PoC
If
stakeis not called in the same block ofnotifyRewardAmount, depending on delay, a portion of rewards will remain unused inside the contract.For example, at time
Xrewards are transferred into the contract. Then some timeYhas passed before the first user stakes. However, the reward period will end atX + rewardsDurationnotX + Y +rewardsDuration.Therefore, the rewards for
Y * rewardRatewill remain un-distributed till the next cycle. If a new reward cycle is never started (e.g. final cycle), then any undistributed amount will remain inside the contract.Recommendation
Consider defining
periodFinishin the firststakethat is done afternotifyRewardAmount, when total deposits are zero.Resolution
Trueo Team: Acknowledged.
-
M-06 Medium Invalid Outcome Voting In voteForDispute DOS Resolved
Description
Council members can cast votes referencing an invalid
_winningPosition, one not recognized by the market. If enough votes align on this invalid outcome, the dispute remains unresolvable.Consequently, it remains open indefinitely, blocking certain system actions (e.g., adding or removing council members) which require all disputes to be closed.
Recommendation
Enforce strict
_winningPositionvalidation invoteForDispute, reverting if_winningPositionfalls outside1toITruthMarket(_market).positionCount().Resolution
Trueo Team: Resolved.
-
M-07 Medium OracleBonds Address Change Mishandles Funds Logical Error Partially resolved
Description
The
setOracleBondsfunction in theTruthMarketManagercontract allows the owner to change theoracleBondsaddress. The problem is that theoracleBondsaddress is hardcoded into markets when they are created.If the address is updated in the
TruthMarketManagercontract, active markets not yet finalized will send and account for resolve, dispute, and escalate bonds to the new address.However, when issuing them back, the old address in the market contract will be used, which will not have the funds or have them accounted for, leading to users losing those funds.
Furthermore, any unclaimed dispute bonds will also be unclaimable because the
OracleCouncilcontract will fetch the new address from theTruthMarketManagercontract, while these dispute bonds are stored in and accounted for in the old contract.Recommendation
If an
oracleBondsupdate is needed, ensure it is performed only when all active markets are finalized and manually handle users' unclaimed disputed bonds, as the normal functionality will not work for pending disputes before the address change.Resolution
Trueo Team: Resolved.
Guardian Team: The
setOracleBondsfunction now verifies that all active markets have settled their bonds before an address update is allowed. However, even with this precaution, any unclaimed dispute bonds become unclaimable. -
M-08 Medium Lacking Incentives For The Escalator Logical Error Acknowledged
Description
Currently, if the escalator is correct, the reward is sent to either the resolver or the disputor. This assumes that the escalator is also the resolver or disputor.
However, considering that the escalator requires a larger bond, it’s possible that the resolver or disputor does not have the required bond, and another party could step in and become the escalator. This third party should be able to receive the reward independently for a correct escalation.
Recommendation
Consider splitting the reward between the disputor/resolver and escalator when escalator is correct.
Resolution
Trueo Team: Acknowledged.
-
M-09 Medium Disputer Cannot Re-Dispute After Reset DOS Acknowledged
Description
When a market is reset following multiple active disputes, a user whose dispute is still considered “open” cannot reclaim their bond because the system only allows bond retrieval after the market is finalized.
As a result, that user remains in a state with an unclaimed (open) dispute bond, which prevents them from initiating a new dispute on a subsequent outcome proposal. This essentially locks them out of further participation in the dispute process for that market.
Recommendation
Enable retrieval or reusability of the bond upon a market reset for disputes that remain open. Specifically, consider allowing users to claim or “migrate” their open dispute bond once the market transitions to a reset state—rather than strictly requiring the market to be finalized.
Resolution
Trueo Team: Acknowledged.
-
M-10 Medium DoS In Dispute Process USDC Is Paused DOS Acknowledged
Description
The market’s dispute and escalation mechanisms rely on the ability to deposit bonds in USDC. If USDC—being a pausable token—is paused, no new bonds can be deposited, effectively blocking any new disputes or escalations.
An attacker can exploit this by proposing a resolution in their favor just before USDC becomes paused; if the pause period extends past the challenge window, the outcome remains uncontested, leading to unjust financial gains for the attacker.
Recommendation
Extend dispute periods when USDC (or any payment token) is paused until transfers become possible again.
Resolution
Trueo Team: Acknowledged.
-
M-11 Medium Risk Of Re-org Attack Reorg Acknowledged
Description
In the case of a block re-org event, disputors may unknowingly have submitted disputes for what they believe to be the correct result, leading to slashing and the loss of their disputor bonds.
For example, consider the following scenario:
(1) Alice proposes an incorrect resolution.
(2) Bob disputes Alice’s resolution.
(3) A block re-org occurs and Alice’s proposal is replaced with a correct resolution.
(4) Bob’s dispute is invalid and will be punished.
Recommendation
Allow disputors to pass the exact position they’d like to dispute to function
openDispute.Resolution
Trueo Team: Acknowledged.
-
M-12 Medium USDC Blacklisted Users Can Freeze Market Transfer Partially resolved
Description
If the market is disputed or escalated, it could transfer bonds back to the disputor and escalator if they are not punished. However, since the
paymentTokenis USDC, which has a blacklist feature, it is possible for the disputor or escalator is blacklisted when the market attempts to return the bonds.This would cause the market state transitions to fail. The same issue could occur when attempting to send rewards to the resolver or disputor if the reward token also has a blacklist feature.
Recommendation
Consider using the Pull-over-Push pattern when handling bonds and rewards.
Resolution
Trueo Team: Resolved.
Guardian Team: The transfer could still be blocked when sending rewards to a blacklisted address.
-
M-13 Medium Market DOS From Direct Reset Or Resolve DOS Resolved
Description
Proof of concept: PoC
A market can be resolved or reset by the owner directly from the
TruthMarketManagercontract. One instance where this will be used is, if a market is paused, only the owner can call the reset or resolve market functions instead of following the general flow through either theOracleCouncilcontract or theEscalationcontract.The issue is that when called directly, the dispute or escalation processes are not fully completed as they would be in the general flow. In the dispute case, for instance, one issue would be the
marketLastClosedDisputenot being updated, meaning theisResolverPunishedandisDisputorPunishedflags remain unset, defaulting tofalse.Consequently, when the market either resets or finalizes, it will attempt to send funds to the disputer’s address fetching the address from the unset
marketLastClosedDispute. Since this address is not set, it would return the zero address, leading to a revert and locking up the market.Furthermore, the
marketClosedForDisputesis also not set totrueas done in the general flow, meaning unclaimed disputes for the market will remain locked.Similarly, in the escalation case, if called directly for either reset or resolve, the lack of updates to
marketToEscalatedDisputewill leave multiple variables such as punishment outcomes empty.This will also cause incorrect outcomes, as the punishment outcomes will all default to false and possibly other issues.
Recommendation
In the current code, a direct call to reset or resolve the market will cause multiple issues, potentially locking up the market and user funds. Either modify the logic to ensure that if called directly, the dispute or escalation processes are still fully completed, or avoid calling them directly entirely.
Resolution
Trueo Team: Resolved.
-
L-01 Low Markets Can Be Created And Cancelled For Profit Logical Error Acknowledged
Description
In the current implementation, market creation is restricted to trusted council members. However, once market creation becomes permissionless as per the documentation, it introduces the risk of abuse.
Malicious actors could create nonsensical or deliberately unresolvable markets and then submit a
CANCELEDresolution to claim resolver feesRecommendation
To mitigate this risk consider implementing a market creation fee when market creation becomes permissionless.
Resolution
Trueo Team: Acknowledged.
-
L-02 Low Bond Amounts Not Validated Validation Acknowledged
Description
Within function
setAmountsin theTruthMarketManager, is it not validated thatescalatorBondAmountis the largest bond amount relative to the disputer and resolver bond amounts.According to documentation, "Every escalation must come at an increased cost to that of the previous, so that the protocol may potentially slash the bonds in compensation for the expended resources."
Recommendation
Validate the bonds amounts to be according to documentation.
Resolution
Trueo Team: Acknowledged.
-
L-03 Low Market Creation Lacks Input Validation Validation Acknowledged
Description
Currently, the
createMarketfunction lacks validation for several input fields, which could lead to the creation of invalid or exploitable markets.Specifically:
rewardTokenshould be a non-zero addressrewardAmountshould not be zero and have a minimum amountyesNoTokenCapshould be of a reasonable amount
Recommendation
Implement validations for the input fields described above.
Resolution
Trueo Team: Acknowledged.
-
L-04 Low Potential Griefing To Mint Transactions Griefing Acknowledged
Description
The
mintfunction is exposed to a griefing attack where an attacker can frontrun a legitimate user's transaction by minting the exact remaining tokens under theyesNoTokenCap. This causes the legitimate user's transaction to revert due to theTokenCapExceeded()check.The attacker can then backrun with a
burntransaction, reclaiming the payment tokens spent during the frontrun. Although this attack requires the attacker to have sufficient capital to mint the remaining tokens, it effectively disrupts legitimate users.Recommendation
Introduce a mechanism to limit how quickly addresses can mint, or limit the maximum mint amount per transaction.
Resolution
Trueo Team: Acknowledged.
-
L-05 Low Access Control Naming Convention Best Practices Acknowledged
Description
Within
OraclePausable, the modifierpauserOnlybreaks the typically access control naming convention ofonlyRoleRecommendation
Consider updating the modifier to
onlyPauser.Resolution
Trueo Team: Acknowledged.
-
L-06 Low Incorrect TrueToken maxSupply Logical Error Acknowledged
Description
The
Truemarketdocumentation states that the total supply of TRUE is 100 million. However, the currentmaxSupplyset in theTrueTokencontract is 1 billion, which contradicts the documentation.Recommendation
Update the
maxSupplyvalue in theTrueTokencontract to align with the documented total supply of 100 million.Resolution
Trueo Team: Acknowledged.
-
L-07 Low Block In _isValidTransition Never Triggered Logical Error Acknowledged
Description
In the
_isValidTransitionfunction, theelseblock for handling transitions when the from status isResetByCouncilis never triggered.This is due to the behavior of
getCurrentStatus, which automatically transitions theResetByCouncilstatus toOpenForResolutionif the current timestamp is past the second challenge period.Furthermore, the logic in the else block is incorrect because, there is no direct transition from
ResetByCounciltoOpenForResolution.Recommendation
Consider removing the
elseblock.Resolution
Trueo Team: Acknowledged.
-
L-08 Low Token Loss Via Truncation In Burn() Function Truncation Acknowledged
Description
When
amountis multiplied by10^paymentTokenDecimalsand then divided by10^tokenDecimals, anyamountsmaller than the ratio10^(tokenDecimals - paymentTokenDecimals)is rounded down to0.As a result, users may burn their YES/NO tokens but receive zero payment tokens, causing them to lose tokens unintentionally.
Recommendation
Require
paymentTokenAmount > 0before executing the burn, it's also recommended to only burn a multiple of10^(tokenDecimals - paymentTokenDecimals)from the users token avoiding loss from their end due to truncation.Resolution
Trueo Team: Acknowledged.
-
L-09 Low Clear Data After Removing Council Member Logical Error Acknowledged
Description
When
removeOracleCouncilMemberis called, it movescouncilMemberAddressatcouncilMemberCounttocouncilMemberIndex[_councilMember], but thecouncilMemberAddressatcouncilMemberCountis not cleared.Recommendation
When removing a council member, consider clearing
councilMemberAddressatcouncilMemberCount.Resolution
Trueo Team: Acknowledged.
-
L-10 Low Mismatched Event Parameter Order Events Acknowledged
Description
In the
setAddressesfunction, theAddressesUpdatedevent is emitted with a specific parameter order. However, the actual arguments passed do not match this order.This causes misalignment between the event’s named parameters and the actual addresses being updated, leading to potential confusion or incorrect off-chain tracking.
Recommendation
Reorder the arguments in the
emit AddressesUpdated(...)call to match the event’s parameter list or update the event definition to align with the actual argument order.Resolution
Trueo Team: Acknowledged.
-
L-11 Low Clear Data After Removing Pauser Logical Error Acknowledged
Description
When
removePauserAddressis called, it movespauserAddressatpauserCounttopauserIndex[_pauserAddress], but thepauserAddressatpauserCountis not cleared.Recommendation
When a pauser is removed, consider clearing
pauserAddressatpauserCountResolution
Trueo Team: Acknowledged.
-
L-12 Low OracleCouncil Can't Pause/Unpause MarketManager Logical Error Acknowledged
Description
The
TruthMarketManagercontract uses theonlyOracleCouncilAndOwnermodifier on the pause and unpause functions, allowing the owner andOracleCounciladdress to call them.However, the
OracleCouncilcontract does not implement the functionality to invoke these functions, preventing it from pausing or unpausing theTruthMarketManagercontract as intended.Recommendation
Implement the necessary functionality in the
OracleCouncilcontract to allow it to call the pause and unpause functions in theTruthMarketManagercontract.Resolution
Trueo Team: Acknowledged.
-
L-13 Low setEndOfTrading Lacks Input Validation Validation Acknowledged
Description
When a market is newly created, it ensures that
_endOfTradingis greater thanminimumTradingDuration. However, whensetEndOfTradingis called, there is no validation, making it possible to configure the market with anendOfTradingthat is less thanminimumTradingDuration.Recommendation
Add the same validation inside
setEndOfTrading.Resolution
Trueo Team: Acknowledged.
-
L-14 Low Missing setPaused Function In Market Manager Logical Error Acknowledged
Description
In
OraclePausable,setPausedcan be called byowner()which is theTruthMarketManagerV2contract. However, this function is not implemented inTruthMarketManagerV2.Recommendation
Consider implementing
setPausedinTruthMarketManagerV2.Resolution
Trueo Team: Acknowledged.
-
L-15 Low Incorrect createdAt Timestamp In Escalations Logical Error Acknowledged
Description
When a new dispute is opened through the
openEscalatedDisputefunction, the dispute’screatedAtis set toblock.timestamp.However, this value is overwritten when the
setEscalationProposalIdfunction is called, which setscreatedAttoblock.timestampagain. As a result, the createdAt variable will not accurately reflect the original time the dispute was created.Recommendation
Ensure that the
createdAtvariable is only set once when the dispute is initially opened through theopenEscalatedDispute.Resolution
Trueo Team: Acknowledged.
-
L-16 Low resolveEscalatedDispute Lacks Input Validation Validation Acknowledged
Description
In the function
resolveEscalatedDispute, the input arguments should be validated to avoid any illogical state.Notably:
_isResultResetand_isResultAcceptshould never be equal- Punish arguments (x3) should never all be
true.
Additionally,
isEscalatedDisputorPunishedshould be set tofalsewhen_isResultAcceptis true - as the escalator should never be punished if the escalation was accepted.Similarly,
isCouncilDisputorPunishedshould be set tofalsewhen_isResultAcceptis false. Punish arguments should be validated to ensure they do not conflict with this.Recommendation
Add the recommended validations to
resolveEscalatedDispute.Resolution
Trueo Team: Acknowledged.
-
L-17 Low Disputes Allow Potential Abuse Validation Acknowledged
Description
Users can open a dispute for a market once a resolution is proposed by calling the
openDisputefunction with the market address and_disputeStringas parameters. The_disputeStringallows users to explain the reason for the dispute and present evidence.However, with no restrictions or validations on the
_disputeString, malicious users could exploit this feature to post malicious or misleading links. If these links are displayed on the front end, they could lead unsuspecting users to phishing sites or other malicious content.Additionally, since only one dispute can be processed and rewarded or punished, the cost of such an attack is limited to the disputer bond amount. A malicious actor could open multiple disputes with different dispute strings to increase the chances of unsuspecting users clicking on the harmful links.
Recommendation
Ensure that disputes displayed on the front end are validated to prevent malicious content from being presented to users.
Resolution
Trueo Team: Acknowledged.
-
L-18 Low Reset By Council Cannot Be Escalated Logical Error Acknowledged
Description
When the council decides to reset a market with
_returnToOpenForResolution == true, market status is immediately set toOpenForResolution.As a result, the decision cannot be disputed by escalation which prevents a confident resolver from disputing the decision, so as not to lose the potential reward.
Recommendation
Consider if this is expected. Otherwise, allow for dispute by escalation, even if the council's decision is to reset and open market for resolution.
Resolution
Trueo Team: Acknowledged.
-
L-19 Low Max Council Members Can Be Violated Logical Error Acknowledged
Description
The
addOracleCouncilMemberfunction incorrectly implements the check for the maximum number of council members, allowing the limit to be exceeded by one.The condition:
if
(councilMemberCount > marketManager.maxOracleCouncilMembers()) revertMaxOracleCouncilMembersExceeded();does not prevent adding an 11th member when the maximum allowed is 10.This happens because the check is only triggered after the count exceeds the limit, rather than when it reaches the limit.
Recommendation
Update the condition to ensure the council member count does not exceed the maximum:
if
(councilMemberCount = marketManager.maxOracleCouncilMembers()) revertMaxOracleCouncilMembersExceeded();Resolution
Trueo Team: Acknowledged.
No findings match.
Invariants 17
The review's fuzzing suite asserted 17 invariants. 13 held and 4 did not.
Every invariant tested
| ID | Invariant | Result |
|---|---|---|
ERR-01 | Only protocol errors allowed | Held |
GLOB-00 | Market status order violated | Broken |
GLOB-01 | After a market reaches status Finalized, it's status should never change. | Held |
GLOB-02 | Should not see any ERC20InsuffcientBalance reverts (specifically from the contract, actor balances should be handled with a sufficient | Held |
GLOB-03 | mint and handler pre-conditions) If MarketStatus == ResetByCouncil then oracleCouncil.getLastClosedDispute(address(t | Held |
GLOB-04 | his)).lastDisputorAddress != address(0) TruthMarket should only hold a rewardToken balance of rewardAmount or 0 | Held |
GLOB-05 | Payment token balance inside the market should always be enough to cover all user's | Held |
GLOB-06 | burn under all market conditions. EscalatedDisputerBondAmount should be equal to disputerBondAmount | Held |
GLOB-07 | DisputorTotalBond should be equal to disputorsCount * disputerBondAmount | Held |
GLOB-08 | Resolution proposed before secondChallengePeriod elapsed after | Broken |
DIS-01 | ResetByCouncil OracleCouncil.voteForDispute - disputeVotesCount should never change if the council member had a prior vote and is | Held |
RES-01 | changing their vote. After a proposeResolution function call the marketBond[_market].totalMarketBond should increase by the | Broken |
RES-02 | ITruthMarket(_marketAddress).resolverBondA mount() After a proposeResolution function call the marketBond[_market].totalDepositedMarketBo nd should increase by the | Broken |
RES-03 | ITruthMarket(_marketAddress).resolverBondA mount() OracleBonds tracking of each market's resolverBond balance should never exceed resolverBond amount. Any violation would | Held |
RES-04 | imply multiple resolutions proposed or failure to refund bond during reset. OracleBonds tracking of each market's escalatedDisputorBond balance should never exceed escalatorBondAmount amount. Any | Held |
REED-01 | violation would imply multiple escalations possible. Payment token balance inside the market should always be enough to cover all user's redeem when market is finalized and winning | Held |
WFCM-01 | position is either YES or NO. Payment token balance inside the market should always be enough to cover all user's withdrawFromCanceledMarket when market is finalized and winning position is CANCELED. | Held |
More from Trueo
Put your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
