Skip to content

exchange_router: multicall has no batch-size cap despite declaring a dedicated BatchSizeLimitExceeded error #575

Description

@abayomicornelius

Problem

exchange_router declares a dedicated error variant for an oversized batch:

BatchSizeLimitExceeded = 5,

but multicall (contracts/exchange_router/src/lib.rs, ~lines 361-395) never checks actions.len() against any bound before dispatching:

pub fn multicall(env: Env, caller: Address, actions: Vec<RouterAction>) -> Vec<BytesN<32>> {
    caller.require_auth();
    ...
    let len = actions.len();
    let mut i = 0u32;
    while i < len {
        let action = actions.get(i).unwrap();
        match action { ... }
        i += 1;
    }
    results
}

grep -n "BatchSizeLimitExceeded" contracts/exchange_router/src/lib.rs matches only the declaration — the error is never constructed or raised anywhere. This is the sibling entrypoint to order_handler::create_orders, which does enforce a batch cap (if requests.len() > 5 { panic_with_error!(&env, Error::BatchSizeLimitExceeded); }, itself tracked separately for using a bare literal instead of a named constant) — multicall's own identically-named error variant suggests the same protection was intended here but was never implemented.

Why it matters

An unbounded actions vector means a single multicall transaction can chain an arbitrary number of SendTokens/CreateDeposit/CreateOrder/etc. actions in one call, each iterating the same DataStore/vault/handler cross-contract calls as the standalone equivalents. Soroban's own per-transaction resource budget is the only backstop — there's no protocol-level cap the way order_handler::create_orders deliberately has one, despite exchange_router having defined (and presumably intended to use) the identical error code for exactly this case.

Scope

In scope

  • contracts/exchange_router/src/lib.rs::multicall — add the missing size check.

Out of scope

  • order_handler::create_orders's own cap, already enforced (tracked separately only for its magic-number style).

Suggested fix

Add a bound check at the start of multicall, e.g. if actions.len() > MAX_MULTICALL_BATCH_SIZE { panic_with_error!(&env, Error::BatchSizeLimitExceeded); }, choosing a sane cap consistent with the resource budget a full batch of the most expensive action type (e.g. CreateOrder) can afford.

Verification

cargo test -p exchange-router

Add a test constructing a batch larger than the chosen cap and asserting multicall reverts with BatchSizeLimitExceeded.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardStellar WaveIssues in the Stellar wave programThird CampaignCampaign: Third CampaignbugSomething isn't workingpriority:lowsize:xs

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions