Skip to content

feat: Add construct-meta-transaction command#562

Merged
frol merged 4 commits intomainfrom
copilot/add-construct-meta-transaction
Feb 27, 2026
Merged

feat: Add construct-meta-transaction command#562
frol merged 4 commits intomainfrom
copilot/add-construct-meta-transaction

Conversation

Copy link
Contributor

Copilot AI commented Feb 27, 2026

There was no way to explicitly construct and sign a meta-transaction (delegate action) — the only path was implicit via meta_transaction_relayer_url in network config. This adds transaction construct-meta-transaction as an explicit command, and consolidates the delegate-action decision into a single context flag so signers don't check two places.

Key changes

  • New construct-meta-transaction command — same CLI structure as construct-transaction (sender, receiver, action chain); reuses add_action_1/2/3/skip_action entirely without duplication; outputs ConstructTransactionContext with sign_as_delegate_action: true

  • sign_as_delegate_action: bool flag propagated through the context chain:

    • ConstructTransactionContextActionContext (via skip_action) → NetworkForTransactionArgsContextTransactionContext
    • Set in NetworkForTransactionArgsContext as context.sign_as_delegate_action || network_config.meta_transaction_relayer_url.is_some(), so the relayer URL config is translated into the flag — signers now check one place only
  • All signers updated (sign_with_keychain, sign_with_legacy_keychain, sign_with_private_key, sign_with_seed_phrase, sign_with_access_key_file, sign_with_ledger) to check previous_context.sign_as_delegate_action instead of network_config.meta_transaction_relayer_url.is_some()

  • submit_dao_proposal and sign_with_mpc now derive sign_as_delegate_action from network_config.meta_transaction_relayer_url.is_some(), preserving existing behavior for those flows when a relayer URL is configured

  • send step now returns a user-facing error instead of panicking when a SignedDelegateAction is produced but no meta_transaction_relayer_url is configured (e.g. when using construct-meta-transaction without a relayer), with a message guiding the user to configure the relayer URL or use transaction send-meta-transaction

Example usage:

near transaction construct-meta-transaction alice.near bob.near \
  add-action transfer 1NEAR \
  skip \
  network-config mainnet \
  sign-with-keychain display
Original prompt

This section details on the original issue you should resolve

<issue_title>[Task] Add construct-meta-transaction</issue_title>
<issue_description>### Background

Meta-transactions on near are basically just a transaction with a single action DelegateAction.

The DelegateAction is basically a SignedTransaction with max_block_height which controls the expiration of the signed payload.

near-cli-rs already has support for creating and sending Meta-transactions if the network config has meta_transaction_relayer_url, so currently signer implementations (e.g. 1) make the decision based on this config setting, but there is no way to explicitly create and sign the Delegate Action.

User Story

As a NEAR CLI user, who uses dApps that support meta-transactions and use NEAR Connect with NEAR CLI plugin, I need CLI to support construction of meta-transactions just like construct-transaction.

Acceptance Criteria

I would like to have a new subcommand under transaction, so next to construct-transaction we could have construct-meta-transaction, the construct-transaction implementations should be reused without copy-pasting them, and the only change that is expected is to the signers implementation that would use the context flag to make the decision whether they should construct & sign a transaction or delegate action. As for the meta_transaction_relayer_url config option, it should be translated into the context flag setting as well, so signers don't need to check two places for the decision.

Resources & Additional Notes

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

- Add sign_as_delegate_action: bool to ConstructTransactionContext, ActionContext, TransactionContext, and NetworkForTransactionArgsContext
- Propagate sign_as_delegate_action through all action chain context structs (add_action_1/2/3)
- Update skip_action to propagate sign_as_delegate_action to ActionContext
- Combine sign_as_delegate_action with meta_transaction_relayer_url check in NetworkForTransactionArgsContext
- Update info_str to use sign_as_delegate_action instead of relayer URL check
- Update all signers to use previous_context.sign_as_delegate_action
- Create construct_meta_transaction module that sets sign_as_delegate_action: true
- Add ConstructMetaTransaction variant to TransactionActions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI changed the title [WIP] Add construct meta-transaction feature Add construct-meta-transaction command Feb 27, 2026
@frol
Copy link
Collaborator

frol commented Feb 27, 2026

image image

It works like a charm! The only problem is that it still suggests to send the delegate action and the user should pick display since if there is no meta_transaction_relayer_url, there is no place to send it to. Maybe the solution would be to just construct the send-meta-transaction <delegate-action> command on send as a fallback instead of crashing with an error, but this could be added in a separate PR.

@frol frol marked this pull request as ready for review February 27, 2026 13:58
@frol frol requested a review from a team as a code owner February 27, 2026 13:58
Copilot AI review requested due to automatic review settings February 27, 2026 13:58
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an explicit transaction construct-meta-transaction CLI command and consolidates meta-transaction (delegate action) signing behavior behind a single propagated sign_as_delegate_action context flag, so signer implementations no longer consult network config directly.

Changes:

  • Introduce construct-meta-transaction under near transaction, reusing the existing construct-transaction action chain while forcing sign_as_delegate_action: true.
  • Propagate sign_as_delegate_action through ConstructTransactionContext → ActionContext → NetworkForTransactionArgsContext → TransactionContext, with network config (meta_transaction_relayer_url) translated into the flag in NetworkForTransactionArgsContext.
  • Update signer implementations to branch on previous_context.sign_as_delegate_action instead of network_config.meta_transaction_relayer_url.is_some().

Reviewed changes

Copilot reviewed 79 out of 79 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/commands/mod.rs Add sign_as_delegate_action to ActionContext and TransactionContext
src/network_for_transaction/mod.rs Compute/propagate sign_as_delegate_action; adjust “Unsigned …” label
src/commands/transaction/mod.rs Register new construct-meta-transaction subcommand
src/commands/transaction/construct_meta_transaction/mod.rs Implement construct-meta-transaction context (forces delegate-action signing)
src/commands/transaction/construct_transaction/mod.rs Add sign_as_delegate_action to construct context (default false)
src/commands/transaction/construct_transaction/skip_action/mod.rs Propagate flag into ActionContext when moving to signing flow
src/commands/transaction/construct_transaction/add_action_1/add_action/use_global_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/transfer/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/stake/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/deploy_global_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/deploy_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/delete_key/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/delete_account/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/create_account/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/call_function/mod.rs Propagate flag through function-call builder contexts
src/commands/transaction/construct_transaction/add_action_1/add_action/add_key/use_public_key/mod.rs Propagate flag through add-key builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/add_key/use_manually_provided_seed_phrase/mod.rs Propagate flag through add-key builder context
src/commands/transaction/construct_transaction/add_action_1/add_action/add_key/access_key_type/mod.rs Propagate flag through access-key permission contexts
src/commands/transaction/construct_transaction/add_action_2/add_action/use_global_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/transfer/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/stake/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/deploy_global_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/deploy_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/delete_key/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/delete_account/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/create_account/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/call_function/mod.rs Propagate flag through function-call builder contexts
src/commands/transaction/construct_transaction/add_action_2/add_action/add_key/use_public_key/mod.rs Propagate flag through add-key builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/add_key/use_manually_provided_seed_phrase/mod.rs Propagate flag through add-key builder context
src/commands/transaction/construct_transaction/add_action_2/add_action/add_key/access_key_type/mod.rs Propagate flag through access-key permission contexts
src/commands/transaction/construct_transaction/add_action_3/add_action/use_global_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/transfer/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/stake/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/deploy_global_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/deploy_contract/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/delete_key/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/create_account/mod.rs Propagate flag through action builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/call_function/mod.rs Propagate flag through function-call builder contexts
src/commands/transaction/construct_transaction/add_action_3/add_action/add_key/use_public_key/mod.rs Propagate flag through add-key builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/add_key/use_manually_provided_seed_phrase/mod.rs Propagate flag through add-key builder context
src/commands/transaction/construct_transaction/add_action_3/add_action/add_key/access_key_type/mod.rs Propagate flag through access-key permission contexts
src/commands/transaction/sign_transaction/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/transaction/send_meta_transaction/sign_as/mod.rs Initialize ActionContext.sign_as_delegate_action
src/transaction_signature_options/sign_with_keychain/mod.rs Use context flag to decide delegate-action vs tx signing
src/transaction_signature_options/sign_with_legacy_keychain/mod.rs Use context flag to decide delegate-action vs tx signing
src/transaction_signature_options/sign_with_private_key/mod.rs Use context flag to decide delegate-action vs tx signing
src/transaction_signature_options/sign_with_seed_phrase/mod.rs Use context flag to decide delegate-action vs tx signing
src/transaction_signature_options/sign_with_access_key_file/mod.rs Use context flag to decide delegate-action vs tx signing
src/transaction_signature_options/sign_with_ledger/mod.rs Use context flag to decide delegate-action vs tx signing
src/transaction_signature_options/sign_with_mpc/mod.rs Add TransactionContext.sign_as_delegate_action initialization
src/transaction_signature_options/submit_dao_proposal/mod.rs Add TransactionContext.sign_as_delegate_action initialization
src/commands/tokens/send_near/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/tokens/send_nft/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/tokens/send_ft/amount_ft.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/deposit_and_stake.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/stake.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/stake_all.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/unstake.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/unstake_all.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/withdraw.rs Initialize ActionContext.sign_as_delegate_action
src/commands/staking/delegate/withdraw_all.rs Initialize ActionContext.sign_as_delegate_action
src/commands/contract/call_function/as_transaction/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/contract/deploy/initialize_mode/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/contract/deploy/initialize_mode/call_function_type/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/contract/deploy_global/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/use_public_key/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/use_manually_provided_seed_phrase/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/use_mpc/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/use_ledger/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/autogenerate_new_keypair/print_keypair_to_terminal/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/autogenerate_new_keypair/save_keypair_to_keychain/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/add_key/autogenerate_new_keypair/save_keypair_to_legacy_keychain/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/create_account/fund_myself_create_account/sign_as/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/delete_account/mod.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/delete_key/public_keys_to_delete.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/storage_management/storage_deposit.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/storage_management/storage_withdraw.rs Initialize ActionContext.sign_as_delegate_action
src/commands/account/update_social_profile/sign_as.rs Initialize ActionContext.sign_as_delegate_action

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

Copy link
Collaborator

@frol frol left a comment

Choose a reason for hiding this comment

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

I am refactoring it a tiny bit, don't merge yet

…remove panic in send

Co-authored-by: frol <304265+frol@users.noreply.github.com>
…ion_relayer_url' is not configured for the network
@frol frol changed the title Add construct-meta-transaction command feat: Add construct-meta-transaction command Feb 27, 2026
@frol frol merged commit ef87d0e into main Feb 27, 2026
13 checks passed
@frol frol deleted the copilot/add-construct-meta-transaction branch February 27, 2026 17:43
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.

[Task] Add construct-meta-transaction

3 participants