Skip to content

feat: OdraCLI upgrade and upgrade-children commands - #696

Merged
kubaplas merged 4 commits into
release/2.10.0from
feat/cli-upgrade
Nov 5, 2026
Merged

kubaplas merged 4 commits into
release/2.10.0from
feat/cli-upgrade

Conversation

@kubaplas

@kubaplas kubaplas commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Closes #690

Upgrading a contract, or all children of a factory, no longer needs a custom scenario:

just cli upgrade Controller --gas 400cspr --force-create-upgrade-group

Changes

  • New upgrade command (odra-cli/src/cmd/upgrade.rs): one subcommand per contract registered with .contract::<T>() or .named_contract::<T>(name). It upgrades the contract at the address in the contracts file with wasm/<Contract>.wasm.
    • Upgrade arguments: taken from the contract's upgrade entry point in its schema and parsed like any other entry point's arguments. A contract without an upgrade fn takes none.
    • --gas: required.
    • --force-create-upgrade-group: off by default.
    • --allow-key-override [BOOL]: defaults to true, as in UpgradeConfig::new. The flag alone also means true; --allow-key-override false turns it off.
    • --package-named-key <NAME>: defaults to the contract name, or to the named_contract name.
    • Output: gas is reset to 0 after the upgrade, --json is supported, and the command works in the REPL.
  • New upgrade-children command (odra-cli/src/cmd/upgrade_children.rs): upgrade-children <Factory> --gas <amount> [--<child upgrade args>]. It's listed only for registered factories, i.e. contracts with batch_upgrade_child_contract.
    • What it does: upgrades all children with the factory's current code in one batch_upgrade_child_contract call. Every child gets the same upgrade arguments, which are the arguments of upgrade_child_contract minus contract_name.
    • Finding the children: from the factory's *ContractDeployed { contract_name, contract_address } events. Each name is listed once, even though an upgrade emits the event again. The event name is matched by suffix, so children created before the factory was upgraded from another module are found too.
    • --batch-size N: one transaction per N children, each with the --gas amount (default: all in one). If a transaction fails, the error lists the children upgraded so far and the ones left.
    • Hidden arguments: it passes the same odra_cfg_* arguments as the generated factory ref (odra_cfg_is_factory_upgrade, odra_cfg_allow_key_override, odra_cfg_create_upgrade_group). odra::consts is now re-exported for this.
  • Fix, contract command on factories: new_contract and upgrade_child_contract failed on chain with MissingArgument, because the generic call didn't send the odra_cfg_* arguments the generated factory ref adds. They're now added for factory contracts, in entry_point::factory, which upgrade-children uses too. batch_upgrade_child_contract is no longer listed under contract: its schema argument type (List<U8>) doesn't match what it actually takes, so it could never be called there. upgrade-children covers it.
  • Core: Deployer::try_upgrade_with_runtime_args upgrades with RuntimeArgs instead of the typed UpgradeArgs. try_upgrade_with_cfg now delegates to it.
  • contract command: upgrade is no longer listed as a callable entry point. Calling it there could not work.
  • CHANGELOG entry. Docs: Docs: Odra 2.10.0 afterparty changes odradev.github.io#60 (new "Upgrade command" section in the Odra CLI tutorial).

Testing

  • Unit tests: cover argument parsing, the required --gas and upgrade arguments, the config defaults and overrides, the named-contract key default, and the error for a contract missing from the contracts file. They use a mock upgrader that records its arguments.
  • cargo test -p odra-cli, clippy, and the upgrade tests in examples pass.
  • upgrade-children tests: only factories are listed, the child upgrade arguments are required and contract_name is rejected, children are read from events (de-duplicated, other events skipped), and the batch arguments are byte-for-byte what the generated factory ref builds.
  • upgrade-children end to end on NCTL (with a temporary deploy script, not committed): deployed BetterCounterFactory with children FromTen (10) and FromTwo. upgrade-children BetterCounterFactory --new_value 42 upgraded both in one transaction and contract FromTen value returned 42. A second run with --json --new_value 7 listed each child once and the value became 7.
  • Factory contract calls and batches, end to end on NCTL (temporary deploy script, not committed): contract BetterCounterFactory new_contract created children A, B and C. contract BetterCounterFactory upgrade_child_contract --contract_name A --new_value 5 changed A from 1 to 5. upgrade-children ... --new_value 9 --batch-size 2 sent 2 transactions (A, B, then C), and A then read 9.
  • End to end on NCTL: ran deploy, then upgrade DogContract --gas 400000000000. The transaction executed, the package hash was unchanged, and contract DogContract name still worked afterwards. --json and --help were also checked.

🤖 Generated with Claude Code

kubaplas and others added 2 commits November 3, 2026 12:32
`upgrade <Contract> --gas <amount>` upgrades a contract from the contracts file with its wasm.
The arguments of the contract's `upgrade` entry point are taken from the command line like
the arguments of any other entry point, and `--force-create-upgrade-group`,
`--allow-key-override` and `--package-named-key` set the `UpgradeConfig`, so upgrading no
longer needs a custom scenario.

`Deployer::try_upgrade_with_runtime_args` upgrades with untyped arguments;
`try_upgrade_with_cfg` delegates to it. The `contract` command no longer lists `upgrade` as
a callable entry point.

Closes #690

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`upgrade-children <Factory> --gas <amount>` upgrades all child contracts of a factory with
the factory's current code, in one `batch_upgrade_child_contract` call. The upgrade
arguments of a child are taken from the command line and passed to every child. The
children are read from the factory's `ContractDeployed` events, listed once even though
an upgrade emits the event again.

`odra::consts` re-exports the names of the `odra_cfg_*` arguments the call needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kubaplas kubaplas changed the title feat: OdraCLI upgrade command feat: OdraCLI upgrade and upgrade-children commands Nov 4, 2026
kubaplas and others added 2 commits November 4, 2026 17:57
…t command

`upgrade-children --batch-size N` sends one `batch_upgrade_child_contract` transaction per
N children. A failed transaction reports the children upgraded so far and the ones left.

The `contract` command calls `new_contract` and `upgrade_child_contract` of a factory with
the `odra_cfg_*` arguments its generated ref adds, which the schema does not list: the calls
failed with `MissingArgument`. `batch_upgrade_child_contract`, whose arguments the schema does
not describe, is no longer listed there; `upgrade-children` runs it. Both commands share the
arguments in `entry_point::factory`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…upgrader

`ContractUpgradeCmd::request` resolves the command line into the upgrade to run (address,
upgrade args, config, gas); `exec` sends it. The tests check the request and no longer need
a function-pointer mock, a thread-local call log or a temporary contracts file.
`test_utils::contracts_container_with` builds a memory-backed container with one contract.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@kubaplas
kubaplas merged commit a66ea9c into release/2.10.0 Nov 5, 2026
8 checks passed
@kubaplas
kubaplas deleted the feat/cli-upgrade branch November 5, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OdraCLI auto upgrade scripts.

2 participants