OpenZeppelin / OpenZeppelin/stellar-contracts

Protocol 28: get_validated_context_by_id won't compile once soroban-sdk moves to 28.x (missing ContractExecutable::ExternalRef arm)

Open Beginner friendly
#865 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
95
Forks
68
Avg merge
4d 42m
Merged PRs (30d)
20

Description

get_validated_context_by_id in packages/accounts/src/smart_account/storage.rs (lines ~288-301) matches Context exhaustively over its 3 top-level variants, but the two CreateContract* arms only destructure executable: ContractExecutable::Wasm(wasm), with no arm and no wildcard for the other ContractExecutable variants:

let required_type = match context.clone() {
    Context::Contract(ContractContext { contract, .. }) => {
        ContextRuleType::CallContract(contract)
    }
    Context::CreateContractHostFn(CreateContractHostFnContext {
        executable: ContractExecutable::Wasm(wasm),
        ..
    }) => ContextRuleType::CreateContract(wasm),
    Context::CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext {
        executable: ContractExecutable::Wasm(wasm),
        ..
    }) => ContextRuleType::CreateContract(wasm),
};

This compiles today because the crate pins soroban-sdk = "27.0.2" (pre-Protocol 28), where ContractExecutable doesn't yet have the ExternalRef variant reachable here. Protocol 28 (CAP-85) adds CONTRACT_EXECUTABLE_EXTERNAL_REF / ContractExecutable::ExternalRef — see the official upgrade guide, which calls out this exact function shape under "Breaking changes":

custom account contracts that parse the authorization context and are not updated for the new executable type will be unable to authorize contract creation that uses an external executable reference

For this specific match, the effect is sharper than "unable to authorize at runtime" — it's a compile error, the day this crate's own soroban-sdk pin moves to 28.x.

Reproduced, not just read

Copied the exact match shape into a minimal standalone crate and compiled it against both versions:

Against soroban-sdk = "27.0.2" (current pin): compiles clean.

#![no_std]
use soroban_sdk::auth::{Context, ContractContext, ContractExecutable, CreateContractHostFnContext, CreateContractWithConstructorHostFnContext};
use soroban_sdk::Env;

pub fn check(_e: &Env, context: Context) -> u32 {
    match context {
        Context::Contract(ContractContext { .. }) => 1,
        Context::CreateContractHostFn(CreateContractHostFnContext {
            executable: ContractExecutable::Wasm(_wasm),
            ..
        }) => 2,
        Context::CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext {
            executable: ContractExecutable::Wasm(_wasm),
            ..
        }) => 3,
    }
}

Against soroban-sdk = "28.0.0-rc.1" (Protocol 28, currently the published pre-release): fails with E0004:

error[E0004]: non-exhaustive patterns: `soroban_sdk::auth::Context::CreateContractHostFn(CreateContractHostFnContext { executable: soroban_sdk::ContractExecutable::ExternalRef(_), .. })` and `soroban_sdk::auth::Context::CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext { executable: soroban_sdk::ContractExecutable::ExternalRef(_), .. })` not covered
  --> src/lib.rs:6:11
   |
 6 |     match context {
   |           ^^^^^^^ patterns ... not covered

Only the Cargo.toml dependency line differs between the two runs ("27.0.2" vs "28.0.0-rc.1"); everything else — including the match shape — is identical to what's in storage.rs today. Happy to open a PR with a soroban-sdk = "28.0.0-rc.1" line in a branch if that's the easiest way to confirm on your end.

Severity, stated plainly

Not exploitable today — soroban-sdk is pinned at 27.0.2, and ExternalRef doesn't exist at that pin. This is a heads-up for whenever the crate's soroban-sdk dependency moves to 28.x for Protocol 28 support (mainnet vote September 16, 2026): the bump itself won't compile until this match gets a third arm (or a wildcard) for ContractExecutable::ExternalRef.

Duplicate check

Searched ContractExecutable ExternalRef non-exhaustive, CreateContractHostFn Protocol 28, and get_validated_context_by_id across this repo's issues (open + closed) — nothing existing.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/accounts/src/smart_account/storage.rs around get_validated_context_by_id and inspect the ContractExecutable match arms. Compare the current soroban-sdk dependency in Cargo.toml with the Protocol 28 behavior, then run the relevant Rust checks against the updated SDK. Done means the crate compiles with the new executable variant handled appropriately without breaking existing authorization context handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
blockchain
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.