Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · November 2025

LayerZero Composer

for Sapience

Guardian's review of LayerZero Composer for Sapience, published November 2025. The report records 7 findings, including 5 low and 2 informational.

Published
Review window
November 10 to 11, 2025
Language
Solidity
Chains
Base, Arbitrum, Polygon
Sector
Derivatives
  • 0 Critical
  • 0 High
  • 0 Medium
  • 5 Low
  • 2 Informational

3 resolved · 4 acknowledged

Scope

2 files in scope · 356 nSLOC
FilenSLOCLines
packages/protocol/src/predictionMarket/resolvers/PredictionMarketLZResolver.sol158215
packages/protocol/src/predictionMarket/resolvers/PredictionMarketLZResolverUmaSide.sol198279

Findings 7

  1. L-01 Low Misleading getPredictionResolution Results Validation Resolved
    Location
    PredictionMarketLZResolver.sol

    Description

    When the getPredictionResolution function is called with an empty encodedPredictedOutcomes array, the function skips the loop and returns (true, NO_ERROR, true). This contradicts validatePredictionMarkets, which reverts on zero markets. If any on-chain consumer relies solely on getPredictionResolution, an empty parlay incorrectly appears as a resolved success.

    Furthermore, there is no maximum length validation as exists in the validatePredictionMarkets function.

    Recommendation

    Consider mirroring the validation in getPredictionResolution: require the array to be non-empty and within configured bounds, or call validatePredictionMarkets internally and propagate its result.

  2. L-02 Low Lacking Receiver Settlement Check Validation Resolved
    Location
    PredictionMarketLZResolver.sol

    Description

    The prediction market side resolver does not enforce immutability of a market resolution once marked settled. A later cross-chain message with assertedTruthfully=true can set resolvedToYes to a different value, flipping an already-settled market outcome. While the configured UMA-side contract should only send one truthful resolution per market, any misconfiguration, replay from a different authorized remote bridge, or future code changes could toggle outcomes and corrupt payouts.

    Recommendation

    Consider adding validation to assert that market.settled is not already true in the marketResolvedCallback function.

  3. L-03 Low Duplicate MarketIds Allowed Validation Acknowledged
    Location
    PredictionMarketLZResolver.sol

    Description

    Neither the validation nor resolution functions reject duplicate marketIds in the encoded PredictedOutcome[]. This can yield ambiguous parlay semantics, allow overcounting a single market multiple times.

    Recommendation

    Track seen marketIds within the loop and reject duplicated entries. Alternatively, deduplicate before processing and enforce a strict normalized format.

  4. L-04 Low Markets Allowed To Re-Resolve Unexpected Behavior Acknowledged
    Location
    PredictionMarketLZResolverUmaSide.sol

    Description

    In the PredictionMarketLZResolverUmaSide resolver, the assertionResolvedCallback function always clears all mappings related to the marketId, which allows for subsequent submissions to the same market.

    This is important to allow untruthful assertions to be re-submitted, however also allows assertions to be submitted for markets after they have already truthfully resolved.

    Recommendation

    To avoid any unexpected behavior, consider only clearing the mappings when the assertion was resolved non-truthfully so that the already truthfully resolved market cannot be re-submitted.

  5. L-05 Low Missing Configuration Updates Configuration Acknowledged
    Location
    PredictionMarketUmaResolver.sol (OOS)

    Description

    In the PredictionMarketUmaResolver contract there is no path to update the config values after it has been set on construction.

    In case the configurations ought to be changed after deployment a new PredictionMarketUmaResolver instance will have to be deployed.

    Recommendation

    Be aware of this limitation for the PredictionMarketUmaResolver address and consider if a configuration setter should be added.

  6. I-01 Informational Incorrect MarketId Warning Warning Acknowledged
    Location
    Global

    Description

    The UMA resolvers cannot validate the marketId correctness since they require resolution through the UMA oracle and the marketId is based upon the keccak256(abi.encodePacked(claim, ":", endTime)) result.

    As a result, matched predictions can pass the _createPrediction function even though they might use an incorrect marketId. Currently there is no pathway for users to be able to escape their matched prediction of an incorrect marketId was used, meaning that if no other market in the parlay resolves to false, and the invalid marketId remains unresolved the collateral for these users would be trapped.

    Recommendation

    Ensure that the marketId used to create orders from the offchain system is always correct and be aware of this risk.

  7. I-02 Informational Unnecessary marketAsserter Superfluous Code Resolved
    Location
    PredictionMarketLZResolverUmaSide.sol

    Description

    In the UMA side LZ Resolver the marketAsserter mapping is used to store the assertor of the marketId assertion, however this value is never used nor exposed to be read.

    Recommendation

    Consider removing the marketAsserter mapping.

More from Sapience

All 6 reports
  1. Foil Vault and Prediction Market

    61 findings2 critical · 3 high 61 findings: 2 critical, 3 high, 7 medium, 26 low, 23 informational
  2. Sapience

    87 findings8 high 87 findings: 8 high, 18 medium, 30 low, 31 informational
  3. Foil Updates

    36 findings2 critical · 4 high 36 findings: 2 critical, 4 high, 7 medium, 23 low
  4. Foil Vault

    35 findings2 critical · 2 high 35 findings: 2 critical, 2 high, 14 medium, 17 low

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.

Get a quote