Kann Audits / Security Review

FactcheckDotFun

FactcheckDotFun Derivatives Security Review

Review of FactCheckExchange order settlement, signature validation, fee enforcement, and treasury-role management.

SolidityEIP-7702ERC-1271May 28, 2025
Download Report Open Report
Audit period
May 28, 2025
Researchers
3 listed
Scope
1 scoped path
Technologies
Solidity, EIP-7702, ERC-1271
Findings
5 documented

Executive summary

What was reviewed

Review of FactCheckExchange order settlement, signature validation, fee enforcement, and treasury-role management.

This page reflects only the scope and review context disclosed in the published report. Fields the report does not provide are omitted rather than inferred; the PDF remains the source of record for issue detail and limitations.

Security is contextual. This report does not guarantee that the protocol is free from vulnerabilities. It applies to the review context documented in the report.

Scope & record

Engagement dossier

Researchers
Kann, Ivan Fitro, Pelz
Technologies
Solidity, EIP-7702, ERC-1271
Category
Derivatives

Files and paths in scope

  • /src/FactCheckExchange.sol

Findings overview

Severity distribution

The counts below are transcribed from the published report. Status and issue detail remain subject to that report’s exact terminology.

FINDINGS05Documented in the published report
Medium: 2Informational: 3
SeverityCount
Critical0
High0
Medium2
Low0
Informational3

Published findings

Findings

Findings below are reproduced from the complete Kann Audits security review. View the full PDF for complete scope, methodology, assumptions, and audit context.

Medium

2 findings
7.1.1

Signature Verification Broken Under EIP-7702 Due to Reliance on isContract Logic

Medium
Description

In the FactCheckExchange.sol contract, the settleMatchedOrders() function attempts to validate orders using signatures by distinguishing EOAs from contracts. It uses the following logic: -If the address has code (isContract returns true), it calls isValidSignature() via ERC-1271. -If the address has no code, it assumes it’s an EOA and uses ECDSA.recover() to verify the signature. This approach breaks under the upcoming Ethereum Pectra upgrade, which includes EIP-7702. EIP- 7702 allows EOAs to temporarily attach code during a transaction, meaning any externally owned account can now appear as a contract at runtime. As a result: A 7702-enabled EOA with temporary code will cause the logic to treat it as a contract. If the code does not implement ERC-1271, the isValidSignature() call will fail. The logic does not fall back to ECDSA.recover(), causing legitimate EOA signatures to be rejected.

StatusAcknowledged

Link to this finding
7.1.2

Lack of Minimum feeRate Check May Allow Orders to be fullfilled without paying any fees

Medium
Description

The settleMatchedOrders function allows the backend to settle matched orders that were created and matched off-chain. While the contract enforces an upper bound for feeRate, it does not enforce a minimum fee rate. This omission allows orders with extremely low feeRate values (e.g., 1 wei) to be matched and settled. As a result, users can effectively bypass protocol fees altogether, undermining protocol revenue and fairness. Since order matching is handled off-chain and executed on-chain by an address with the BACK- END_ROLE, malicious or careless matching could lead to widespread abuse of low-fee orders.

Recommendation

Introduce a minFeeRate variable, configurable by protocol administrators, and enforce it during order validation to ensure all orders pay at least a minimum protocol fee: require(order.feeRate >= minFeeRate, "Fee rate below minimum allowed");

Resolution

Fixed

7.2 Informational

Informational

3 findings
7.2.1

Missing Market ID Consistency Check in settleMatchedOrders

Informational
Description

The settleMatchedOrders function doesn’t enforce that all makerOrders share the same marketId as the provided takerOrder. While it correctly verifies signature validity and array length consistency, it does not validate that each makerOrder.marketId equals takerOrder.marketId.

Recommendation

for (uint i = 0; i < makerOrders.length; i++) { require( makerOrders[i].marketId == takerOrder.marketId, "FactCheckExchange: Market ID mismatch" ); }

StatusAcknowledged

Link to this finding
7.2.2

Ensure Taker and Maker Orders Are on Opposite Sides

Informational
Description

In the settleMatchedOrders function, there is currently no check to enforce that the takerOrder and each makerOrder are on opposite sides of the trade (i.e., one is a buyer, the other is a seller). While it may be assumed that the backend prevents invalid matches, relying solely on off-chain guarantees can introduce hidden risks.

Recommendation

require(takerOrder.side != makerOrder.side, "Orders must be on opposite sides");

StatusAcknowledged

Link to this finding
7.2.3

Old Treasury Doesn’t Get Revoked When Updated To New One

Informational
Description

In the updateTreasuryWallet() function, the contract sets a new treasuryWallet address and grants it the TREASURY_ROLE However, the role from the previous treasury address is not revoked. As a result, any previously assigned treasury address retains the TREASURY_ROLE

Recommendation

Revoke the old treasuryWallet.

Methodology

How Kann Audits reviews code

Kann Audits reports describe independent researcher review followed by collaborative analysis of findings and attack paths. The standard review foundation includes:

  1. 01Architecture and trust-boundary analysis
  2. 02Independent manual review
  3. 03State-transition and invariant analysis
  4. 04Access-control and integration review
  5. 05Adversarial testing and attack-path analysis
  6. 06Fix verification and regression review

Audit team

Researchers listed in the report

KannIvan FitroPelz

Final assessment

Documented outcome

Two findings were fixed and three were acknowledged.

The assessment applies only to the review context and limitations documented in the published report. Missing details are not inferred, and later changes require separate analysis.

Start a conversation

Planning your next release?

Share the system, fixed scope, and target date. Build enough time into the plan for review, remediation, and verification.