Fastlane

atlas

Cantina Security Report

Organization

@Fastlane

Engagement Type

Cantina Reviews

Period

-


Findings

Medium Risk

2 findings

2 fixed

0 acknowledged

Low Risk

2 findings

2 fixed

0 acknowledged

Informational

4 findings

3 fixed

1 acknowledged

Gas Optimizations

1 findings

1 fixed

0 acknowledged


Medium Risk2 findings

  1. Solvers may receive less gas than they expect

    Severity

    Severity: Medium

    Submitted by

    Riley Holterhus


    Description

    A key change introduced in Atlas V1.6 is that the gas limit forwarded to solvers is now set as the minimum of solverOp.gas (the value set by the solver) and dConfig.solverGasLimit (the value from the DAppControl).

    One consequence of this change is that if dConfig.solverGasLimit is lowered after a solver signs and submits their solverOp, the gas limit they ultimately receive will be lower than they expect. In a worst-case scenario, a DAppControl could intentionally lower the dConfig.solverGasLimit value to cause the solverOp to fail due to an out-of-gas error. This could grief the solver since an out-of-gas error would be treated as their fault.

    Recommendation

    Consider adding a field to the userOp struct to commit to the expected dConfig.solverGasLimit from the DAppControl, similar to how bundlerSurchargeRate is included in the userOp. This approach would only add one new field and ensures that all solverOps are aware of the expected dConfig.solverGasLimit, since it contributes to the userOp hash.

    Fastlane

    Fixed in commit 1ef75ad and commit 8b217b3.

    Cantina Managed

    Verified.

  2. Net repayments can be counted across multiple solverOps

    State

    Fixed

    PR #482

    Severity

    Severity: Medium

    Submitted by

    Riley Holterhus


    Description

    A solverOp's balance is considered reconciled if all current repayments are at least equal to all current borrows, and the solver has also prepaid their maximum gas liability, either through approving their bonded atlETH or with an excess repayment. This is implemented in the following code:

    function _isBalanceReconciled() internal view returns (bool) {   // ....    return (bL.repays >= bL.borrows) && (_maxApprovedGasValue + _netRepayments >= gL.solverGasLiability());}

    However, this logic does not function correctly when multipleSuccessfulSolvers == true, because the same net repayment can be counted toward multiple solverOps.

    For example, if one solverOp leaves behind a 1 ETH net repayment and there are 10 solverOps, each can independently apply the same 1 ETH toward their own gas liability check. There is no mechanism to track how much of the repayment each solverOp is relying on, which allows the same ETH to be reused across multiple solverOps. As a result, _isBalanceReconciled() may incorrectly return true for all solverOps, even if the excess is only sufficient to cover one.

    This can lead to a shortfall in the gas reimbursement that only becomes apparent during the final _settle() call, at which point the bundler would implicitly cover the difference.

    Recommendation

    Change the gas accounting logic so that after each solverOp, the portion of the net repayment used toward its gas liability is subtracted out, preventing other solverOps from reusing the same amount.

    Fastlane

    Fixed in PR 482 and PR 483.

    Cantina Managed

    Verified. The chosen fix is to exclude net repayments from the gas liability check when multipleSuccessfulSolvers == true, which also fixes the issue.

Low Risk2 findings

  1. solverGasLiability() overestimated when multipleSuccessfulSolvers == true

    State

    Fixed

    PR #480

    Severity

    Severity: Low

    Submitted by

    Riley Holterhus


    Description

    The solverGasLiability() function estimates the upper bound amount of gas a successful solver must pay. Its implementation predates the multipleSuccessfulSolvers == true configuration option and assumes a successful solver must cover all overhead gas costs (e.g. userOp and dapp hook costs). However, when multipleSuccessfulSolvers is true, solvers only need to pay for their own calldata and execution gas costs. As a result, the current implementation overestimates the gas liability and requires larger prepayments than necessary.

    Recommendation

    Consider updating the accounting logic so that when multipleSuccessfulSolvers == true, successful solvers only need prepay their own execution and calldata costs.

    Fastlane

    Fixed in PR 480 by changing the _initialRemainingMaxGas value set at the start of a metacall.

    Cantina Managed

    Verified.

  2. Unsafe typecasts

    Severity

    Severity: Low

    Submitted by

    Blockdev


    Description

    Several variables are downcasted from uint256 to uint40 and there are no guarantees for some of them to not overflow. Hence, it's better to use SafeCast.

    Recommendation

    Use SafeCast to revert if variables overflow uint40.

    Fastlane

    Fixed in commit 5728314 and commit fb9eac9.

    Cantina Managed

    Verified.

Informational4 findings

  1. Unused surcharge mask constants

    Severity

    Severity: Informational

    Submitted by

    Riley Holterhus


    Description

    The _ATLAS_SURCHARGE_MASK and _BUNDLER_SURCHARGE_MASK constants in AtlasConstants are unused. These variables are no longer relevant because the bundler surcharge is now a configurable value in the DAppControl instead of being stored in Atlas, and the Atlas surcharge isn't in a packed storage variable.

    Recommendation

    Consider removing the unused _ATLAS_SURCHARGE_MASK and _BUNDLER_SURCHARGE_MASK variables.

    Fastlane

    Fixed in commit b036575.

    Cantina Managed

    Verified.

  2. Incorrect comments in _verifyCallConfig()

    Severity

    Severity: Informational

    Submitted by

    Riley Holterhus


    Description

    The multipleSuccessfulSolvers configuration option is not allowed when allowsZeroSolvers, allowsSolverAuctioneer, or needsFulfillment are true. While this logic is correctly enforced in the code, the related comments for these three options incorrectly reference invertsBidValue instead.

    Recommendation

    Update the comments to reference the correct disallowed options.

    Fastlane

    Fixed in commit 5613618.

    Cantina Managed

    Verified.

  3. Analytics consider all solvers as failed when multipleSuccessfulSolvers == true

    State

    Acknowledged

    Severity

    Severity: Informational

    Submitted by

    Riley Holterhus


    Description

    When multipleSuccessfulSolvers is true, the gas accounting is handled as if all solverOps reverted. This can be seen by the fact that _executeSolverOperation() always calls _handleSolverFailAccounting() when multipleSuccessfulSolvers == true, regardless of whether the solverOp succeeded or failed.

    One side effect of this is that the analytics are also updated as if every solver failed, even though some of the solvers may have succeeded and some of them may have failed.

    Recommendation

    Consider updating the logic so that when multipleSuccessfulSolvers is true, the analytics correctly distinguish between successful and failed solvers.

    Fastlane

    Acknowledged.

    Cantina Managed

    Acknowledged.

  4. Missing Natspec

    Severity

    Severity: Informational

    Submitted by

    Blockdev


    Description

    A new argument multipleSuccessfulSolvers is added to _settle() but it's not added to its Natspec.

    Recommendation

    Add Natspec for multipleSuccessfulSolvers.

    Fastlane

    Fixed in commit 9dbafd.

    Cantina Managed

    Verified.

Gas Optimizations1 finding

  1. Use OZ Math.min()

    Severity

    Severity: Gas optimization

    Submitted by

    Blockdev


    Description

    OZ's Math.min() can be used instead of the ternary operator to compute a minimum of two values. It's easier to read and may also save some gas as Math.min() avoids JUMPs.

    Recommendation

    Use Math.min().

    Fastlane

    Fixed here 482c43b8d9850eb2d2d1abccb7850fb3bf715308.

    FYI it's also relevant to Escrow.sol, AtlasVerification.sol, Simulator.sol, and Sorter.sol.

    Cantina Managed

    Verified.