Skip to content

feat: gas-key support (nearcore 2.13)#607

Merged
r-near merged 10 commits into
mainfrom
feat/gas-keys
Jul 2, 2026
Merged

feat: gas-key support (nearcore 2.13)#607
r-near merged 10 commits into
mainfrom
feat/gas-keys

Conversation

@r-near

@r-near r-near commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Cause

nearcore 2.13 (protocol v85) introduces gas keys: an access-key permission that
carries its own NEAR balance and N parallel nonces. near-cli has no way to
create one, fund it, or inspect its nonces.

Fix

Stacked on the nearcore-2.13 branch (#605):

  • Createaccount add-key gains two permission variants,
    grant-gas-key-full-access and grant-gas-key-function-call, that build an
    AddKey action with AccessKeyPermission::GasKeyFullAccess /
    GasKeyFunctionCall. Gas keys are created empty (the protocol rejects an
    AddKey with a non-zero gas-key balance), so there is no balance argument;
    fund the key afterwards with fund-gas-key. The function-call variant takes a
    contract id and method names but no allowance (the protocol rejects an
    allowance on a gas-key function-call key). The parallel-nonce count is
    collected as u64 (interactive-clap has no ToCli for u16) and narrowed to
    NonceIndex with a 1..=MAX_NONCES_FOR_GAS_KEY bound check.
  • Fundaccount fund-gas-key transfers NEAR from the account into a gas
    key's balance.
  • Withdrawaccount withdraw-from-gas-key moves NEAR from a gas key's
    balance back to the account.
  • Viewaccount view-gas-key-nonces <account> <public-key> issues the
    view_gas_key_nonces query (via the generic QueryRequest::ViewGasKeyNonces
    path) and prints the per-index nonces from GasKeyNoncesView.

Signing a transaction with a specific GasKeyNonce (DelegateV2 / parallel-nonce
signing) remains a follow-up increment.

@github-project-automation github-project-automation Bot moved this to NEW❗ in DevTools Jun 23, 2026
@r-near r-near changed the base branch from pq/post-quantum-keys to main July 2, 2026 00:37
@r-near r-near marked this pull request as ready for review July 2, 2026 00:50
@r-near r-near requested a review from a team as a code owner July 2, 2026 00:50
Copilot AI review requested due to automatic review settings July 2, 2026 00:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates near-cli-rs for nearcore 2.13 / protocol v85 by adding first-class support for new protocol features: gas keys (including creation and nonce inspection) and post-quantum ML-DSA-65 key generation, alongside a set of required primitives/query adaptations and build pipeline tweaks.

Changes:

  • Add gas-key CLI flows: create gas-key permissions in account add-key, fund/withdraw gas-key balances, and query/print parallel nonces via ViewGasKeyNonces.
  • Add signature-scheme plumbing (Ed25519 vs ML-DSA-65), including a new offline generate-keypair command and updated autogeneration flows.
  • Bump nearcore-related dependencies to 0.37.0-rc.2 / matching git revisions, and update query/action handling for nearcore 2.13 changes (DelegateV2, ViewState after_key/limit, etc.).

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/transaction_signature_options/sign_with_mpc/mod.rs Reject ML-DSA-65 for MPC signing; document/guard unsupported key type.
src/common.rs Introduce SignatureScheme + GeneratedKeyPair, gas-key nonce query plumbing, updated error mappings, and ViewState arg updates.
src/commands/transaction/reconstruct_transaction/mod.rs Explicitly reject reconstructing DelegateV2 transactions.
src/commands/mod.rs Register new top-level generate-keypair command module/variant.
src/commands/generate_keypair/mod.rs New offline keypair generation command (Ed25519 / ML-DSA-65) with print/save modes and tests.
src/commands/contract/view_storage/output_format/mod.rs Adapt ViewState query to include after_key/limit.
src/commands/account/withdraw_from_gas_key/mod.rs New command to withdraw from a gas key balance back to the owning account.
src/commands/account/view_gas_key_nonces/mod.rs New command to query and display per-index gas-key nonces.
src/commands/account/mod.rs Wire new gas-key account subcommands into the account command tree.
src/commands/account/fund_gas_key/mod.rs New command to transfer funds into a gas key balance.
src/commands/account/delete_key/public_keys_to_delete.rs Adapt delete-key picker to PublicKeyHandle and skip ML-DSA-65 entries lacking full pubkeys.
src/commands/account/create_account/sponsor_by_faucet_service/add_key/autogenerate_new_keypair/mod.rs Add --signature-scheme to autogenerate flow and use GeneratedKeyPair for output/save.
src/commands/account/create_account/fund_myself_create_account/add_key/autogenerate_new_keypair/mod.rs Same signature-scheme + GeneratedKeyPair adaptation for fund-myself flow.
src/commands/account/add_key/mod.rs Add gas-key permission variants to account add-key.
src/commands/account/add_key/autogenerate_new_keypair/save_keypair_to_legacy_keychain/mod.rs Persist generated keys via GeneratedKeyPair (supports ML-DSA-65 minimal JSON).
src/commands/account/add_key/autogenerate_new_keypair/save_keypair_to_keychain/mod.rs Same as above for keychain save path.
src/commands/account/add_key/autogenerate_new_keypair/print_keypair_to_terminal/mod.rs Print generated key info via GeneratedKeyPair::terminal_info().
src/commands/account/add_key/autogenerate_new_keypair/mod.rs Add --signature-scheme to add-key autogeneration flow.
src/commands/account/add_key/access_key_type/mod.rs Add gas-key access-key permission builders and nonce-count validation.
Cargo.toml Bump/pin nearcore 2.13-related dependencies (rc + git revisions).
Cargo.lock Lockfile updates for new dependency graph (incl. aws-lc-sys-related additions).
.github/workflows/release.yml Set AWS_LC_SYS_PREBUILT_NASM=1 to support Windows builds with aws-lc-sys.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/commands/account/add_key/access_key_type/mod.rs Outdated
Comment thread src/commands/account/add_key/access_key_type/mod.rs
Comment thread src/commands/account/mod.rs
Comment thread src/commands/account/mod.rs
Comment thread src/commands/account/view_gas_key_nonces/mod.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8089185e20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/commands/account/add_key/access_key_type/mod.rs Outdated
r-near added 4 commits July 1, 2026 18:39
Add the first increment of nearcore 2.13 gas-key support:

- account add-key: new grant-gas-key-full-access and
  grant-gas-key-function-call permission variants, building an AddKey
  action with AccessKeyPermission::GasKeyFullAccess / GasKeyFunctionCall
  (balance + parallel-nonce count via GasKeyInfo).
- account view-gas-key-nonces: issues the view_gas_key_nonces query and
  prints the per-index nonces from GasKeyNoncesView.
Add the funding side of gas-key support:

- account fund-gas-key: builds Action::TransferToGasKey
  (TransferToGasKeyAction { public_key, deposit }) to move NEAR into a
  gas key's balance.
- account withdraw-from-gas-key: builds Action::WithdrawFromGasKey
  (WithdrawFromGasKeyAction { public_key, amount }) to move NEAR from a
  gas key's balance back to the owning account.

Both are plain action-builders (owner is signer == receiver) routed
through the normal ActionContext / signing flow, mirroring tokens
send-near. No nonce/signing-layer changes.
The protocol rejects an AddKey that sets a non-zero gas-key balance
("Adding a gas key with non-zero balance is not allowed"), so the
--balance arg on grant-gas-key-full-access / grant-gas-key-function-call
was a footgun. Construct GasKeyInfo with balance 0 unconditionally and
drop the balance input; gas keys are funded after creation via
fund-gas-key.
near-jsonrpc-client =0.22.0-rc.1, near-socialdb-client =0.16.0-rc.1, nearcore =0.37.0-rc.2 (drop git-rev pins)
r-near added 6 commits July 1, 2026 19:04
The keychain entry name and legacy-keychain file name were the full
~1952-byte ML-DSA-65 public key. That overflows filesystem name limits
(File name too long) and never matches the ml-dsa-65-hash:... handle the
RPC access-key list reports, so a saved key could not be found again for
signing. Save autogenerated keys under GeneratedKeyPair::keychain_key_id()
- the full key for ed25519 (unchanged), the on-trie handle for ML-DSA-65 -
which is exactly what sign_with_keychain / the legacy signer look up by.
"fetch query GasKeyNonces" read like an internal type; say "fetch the gas
key nonces" instead.
…n_id

The old comment implied the only caller was the signing-payload match.
near_key_type_to_mpc_domain_id is also called by derive_public_key; note
that both paths exclude ML-DSA-65 (the payload match errors on it, and
derive_public_key only receives a key type chosen from MpcKeyType, which
offers ed25519 / secp256k1 only).
Every near-* crate is now on an exact `=` 2.13 pre-release pin with no git
deps; state that instead of the earlier mixed git/registry wording.
The prompt hardcoded 1..=1024; format it from
AccessKeyPermission::MAX_NONCES_FOR_GAS_KEY (the same constant validation
uses) so it stays correct if the protocol limit changes.
The protocol rejects an AddKey that sets an allowance on a gas-key
function-call key (GasKeyFunctionCallAllowanceNotAllowed); a gas key pays
gas from its own balance. Drop the --allowance arg/prompt for
grant-gas-key-function-call and always build the permission with
allowance: None (receiver_id / method_names still apply).
@r-near r-near merged commit 9905966 into main Jul 2, 2026
13 checks passed
@r-near r-near deleted the feat/gas-keys branch July 2, 2026 02:23
@github-project-automation github-project-automation Bot moved this from NEW❗ to Shipped 🚀 in DevTools Jul 2, 2026
r-near added a commit that referenced this pull request Jul 2, 2026
## Cause

A gas key (nearcore 2.13 / protocol v85) pays for transactions from its
own
balance and uses N parallel nonces. Signing a transaction with one
requires a
versioned (V1) transaction whose nonce is `TransactionNonce::GasKeyNonce
{ nonce,
nonce_index }`; near-cli only ever builds the legacy (V0)
`TransactionNonce::Nonce`
transaction, so a gas key can be created/funded but not used to sign.

## Fix

A single shared nonce resolver in `transaction_signature_options` that
all six
`sign_with_*` modules call, keeping the gas-key + tx-version logic in
one place:

- `resolve_online_nonce()` queries the access key; an ordinary key
resolves to
`nonce + 1` and a V0 transaction (unchanged behavior). A gas key
additionally
queries `view_gas_key_nonces` and resolves to `nonces[nonce_index] + 1`.
- `build_unsigned_transaction()` wraps the
(post-`on_before_signing_callback`)
  `TransactionV0` into a V0 transaction for an ordinary nonce, or a V1
  transaction with `GasKeyNonce` (+ default `NonceMode`) for a gas key.

Each signer gains an optional `--nonce-index <N>` (default 0; `u64`
narrowed to
`NonceIndex` with a bound check, per the interactive-clap `ToCli`
constraint) and
otherwise just calls the resolver and the builder — the gas-key path is
invisible
to the six modules.

## Verification

The signing path can't be unit-tested against RPC, so compile + clippy
is the CI
gate here (`cargo check --tests --no-default-features` [+`--features
ledger`],
`cargo fmt --all --check`, `cargo clippy -- -D warnings` all pass).
Manual
sandbox/testnet verification of an end-to-end gas-key-signed transaction
is
recommended before this leaves draft.

Stacked on #607 (fund/withdraw). Draft.
r-near added a commit that referenced this pull request Jul 2, 2026
## 🤖 New release

* `near-cli-rs`: 0.27.0 -> 0.28.0 (⚠ API breaking changes)

### ⚠ `near-cli-rs` breaking changes

```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---

Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
        ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/constructible_struct_adds_field.ron

Failed in:
  field CliSignPrivateKey.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_private_key/mod.rs:5
  field InteractiveClapContextScopeForGenerateKeypair.signature_scheme in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/create_account/sponsor_by_faucet_service/add_key/autogenerate_new_keypair/mod.rs:3
  field CliSignLedger.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_ledger/mod.rs:18
  field CliSignLegacyKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_legacy_keychain/mod.rs:12
  field CliSignKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_keychain/mod.rs:9
  field SignLedgerContext.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_ledger/mod.rs:51
  field InteractiveClapContextScopeForSignSeedPhrase.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_seed_phrase/mod.rs:7
  field CliSignAccessKeyFile.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_access_key_file/mod.rs:5
  field CliGenerateKeypair.signature_scheme in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/create_account/sponsor_by_faucet_service/add_key/autogenerate_new_keypair/mod.rs:3
  field InteractiveClapContextScopeForSignPrivateKey.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_private_key/mod.rs:5
  field InteractiveClapContextScopeForSignLedger.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_ledger/mod.rs:18
  field InteractiveClapContextScopeForSignLegacyKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_legacy_keychain/mod.rs:12
  field InteractiveClapContextScopeForSignKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_keychain/mod.rs:9
  field InteractiveClapContextScopeForSignAccessKeyFile.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_access_key_file/mod.rs:5
  field CliSignSeedPhrase.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_seed_phrase/mod.rs:7

--- failure enum_no_repr_variant_discriminant_changed: enum variant had its discriminant change value ---

Description:
The enum's variant had its discriminant value change. This breaks downstream code that used its value via a numeric cast like `as isize`.
        ref: https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/enum_no_repr_variant_discriminant_changed.ron

Failed in:
  variant TopLevelCommandDiscriminants::Extensions 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:60
  variant TopLevelCommandDiscriminants::Extensions 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:60
  variant AccountActionsDiscriminants::GetPublicKey 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:69
  variant AccountActionsDiscriminants::AddKey 8 -> 9 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:74
  variant AccountActionsDiscriminants::DeleteKeys 9 -> 12 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:89
  variant AccountActionsDiscriminants::ManageStorageDeposit 10 -> 13 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:94
  variant AccountActionsDiscriminants::GetPublicKey 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:69
  variant AccountActionsDiscriminants::AddKey 8 -> 9 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:74
  variant AccountActionsDiscriminants::DeleteKeys 9 -> 12 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:89
  variant AccountActionsDiscriminants::ManageStorageDeposit 10 -> 13 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:94

--- failure enum_variant_added: enum variant added on exhaustive enum ---

Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/enum_variant_added.ron

Failed in:
  variant AccountActionsDiscriminants:ViewGasKeyNonces in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:64
  variant AccountActionsDiscriminants:FundGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:79
  variant AccountActionsDiscriminants:WithdrawFromGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:84
  variant AccountActionsDiscriminants:ViewGasKeyNonces in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:64
  variant AccountActionsDiscriminants:FundGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:79
  variant AccountActionsDiscriminants:WithdrawFromGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:84
  variant CliTopLevelCommand:GenerateKeypair in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:16
  variant CliAccountActions:ViewGasKeyNonces in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:27
  variant CliAccountActions:FundGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:27
  variant CliAccountActions:WithdrawFromGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:27
  variant TopLevelCommandDiscriminants:GenerateKeypair in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:56
  variant TopLevelCommandDiscriminants:GenerateKeypair in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:56

--- failure function_missing: pub fn removed or renamed ---

Description:
A publicly-visible function cannot be imported by its prior path. A `pub use` may have been removed, or the function itself may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/function_missing.ron

Failed in:
  function near_cli_rs::transaction_signature_options::send::sleep_after_error, previously in file /tmp/.tmppWZUdR/near-cli-rs/src/transaction_signature_options/send/mod.rs:193

--- failure trait_method_added: pub trait method added ---

Description:
A non-sealed public trait added a new method without a default implementation, which breaks downstream implementations of the trait
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#trait-new-item-no-default
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/trait_method_added.ron

Failed in:
  trait method near_cli_rs::common::RpcQueryResponseExt::gas_key_nonces_view in file /tmp/.tmpat9wFR/near-cli-rs/src/common.rs:3499
```

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

##
[0.28.0](v0.27.0...v0.28.0)
- 2026-07-02

### Added

- sign transactions with a gas key (nonce_index)
([#608](#608))
- gas-key support (nearcore 2.13)
([#607](#607))
- post-quantum (ML-DSA-65) key generation (draft)
([#605](#605))
- Validate beneficiary account before deleting account
([#596](#596))

### Fixed

- Fixed output information for transaction status "Started"
([#594](#594))

### Other

- Fixed NPM Trusted Publishing
([#603](#603))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

---------

Co-authored-by: r-near <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Shipped 🚀

Development

Successfully merging this pull request may close these issues.

3 participants