From 9c9f41b3ed4ebbb6fda400bb5e778583419306a8 Mon Sep 17 00:00:00 2001 From: 0xMars42 <195151467+0xMars42@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:38:45 +0200 Subject: [PATCH 1/3] refactor(cast): deduplicate Tempo boilerplate Four mechanical extractions, behavior unchanged: - The Tempo provider construction was spelled out at 33 call sites across the cast commands; `tempo_provider(&config)` in the shared tempo module owns it, the keychain doctor's error-matching variant included. - `print_payload` existed as three identical copies in the tip403, receive-policy and storage-credits commands; one copy lives in the shared tempo module. - Seven keychain hardfork gates repeated the same check-and-bail block; `ensure_tempo_hardfork` owns it, and `ensure_tempo_precompile_active` merges the near-identical T6/T7 precompile guards of the receive-policy and storage-credits commands, code-presence fallback included. - Inside `send_tip20_transaction`, the sponsor fee-token-and-attach block was copied in three of the four send paths and the signer resolution in two; `attach_sponsor` and `resolve_send_signer` own them. The four send paths themselves stay separate, they dispatch differently. --- crates/cast/src/args.rs | 7 +- crates/cast/src/cmd/batch_mktx.rs | 4 +- crates/cast/src/cmd/batch_send.rs | 4 +- crates/cast/src/cmd/erc20.rs | 7 +- crates/cast/src/cmd/keychain.rs | 129 ++++++++++++++++++------- crates/cast/src/cmd/receive_policy.rs | 38 +++----- crates/cast/src/cmd/storage_credits.rs | 43 +++------ crates/cast/src/cmd/tip20/create.rs | 8 +- crates/cast/src/cmd/tip20/logo.rs | 13 ++- crates/cast/src/cmd/tip20/mine.rs | 4 +- crates/cast/src/cmd/tip20/mod.rs | 105 ++++++++++++-------- crates/cast/src/cmd/tip403.rs | 17 +--- crates/cast/src/cmd/vaddr/create.rs | 4 +- crates/cast/src/cmd/vaddr/resolve.rs | 10 +- crates/cast/src/cmd/vaddr/watch.rs | 6 +- crates/cast/src/cmd/wallet/session.rs | 12 +-- crates/cast/src/tempo.rs | 29 +++++- 17 files changed, 251 insertions(+), 189 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 4a8b6f3ff3ef1..040de3081cfd9 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -2,6 +2,7 @@ use crate::{ Cast, SimpleCast, cmd::erc20::IERC20, opts::{Cast as CastArgs, CastSubcommand, ToBaseArgs}, + tempo::tempo_provider, traces::identifier::SignaturesIdentifier, tx::CastTxSender, }; @@ -422,8 +423,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { .await? } Some(NetworkVariant::Tempo) => { - let provider = - ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; Cast::new(&provider) .block_raw(block.unwrap_or(BlockId::Number(Latest)), full) .await? @@ -729,8 +729,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { .await? } Some(NetworkVariant::Tempo) => { - let provider = - ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; Cast::new(&provider) .transaction(tx_hash, from, nonce, field, is_raw, to_request, lane) .await? diff --git a/crates/cast/src/cmd/batch_mktx.rs b/crates/cast/src/cmd/batch_mktx.rs index 235244b289dbc..1fc50470c012d 100644 --- a/crates/cast/src/cmd/batch_mktx.rs +++ b/crates/cast/src/cmd/batch_mktx.rs @@ -6,6 +6,7 @@ use crate::{ call_spec::CallSpec, tempo, + tempo::tempo_provider, tx::{self, CastTxBuilder}, }; use alloy_consensus::SignableTransaction; @@ -22,7 +23,6 @@ use foundry_cli::{ }; use foundry_common::{ FoundryTransactionBuilder, - provider::ProviderBuilder, tempo::{maybe_print_fee_token, resolve_and_set_fee_token}, }; use foundry_wallets::{TempoAccessKeyConfig, WalletOpts, WalletSigner}; @@ -76,7 +76,7 @@ impl BatchMakeTxArgs { } let config = eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; // Resolve `--tempo.lane ` against the lanes file (default // `/tempo.lanes.toml`) and populate `tx.tempo.nonce_key` from the lane. diff --git a/crates/cast/src/cmd/batch_send.rs b/crates/cast/src/cmd/batch_send.rs index af9d359a52721..6f9529458e6c2 100644 --- a/crates/cast/src/cmd/batch_send.rs +++ b/crates/cast/src/cmd/batch_send.rs @@ -8,6 +8,7 @@ use crate::{ call_spec::CallSpec, cmd::send::{cast_send, cast_send_with_access_key}, tempo, + tempo::tempo_provider, tx::{self, CastTxBuilder, SendTxOpts}, }; use alloy_network::{EthereumWallet, TransactionBuilder}; @@ -19,7 +20,6 @@ use foundry_cli::{ opts::TransactionOpts, utils::{self, LoadConfig, maybe_print_resolved_lane, resolve_lane}, }; -use foundry_common::provider::ProviderBuilder; use std::time::Duration; use tempo_alloy::TempoNetwork; @@ -69,7 +69,7 @@ impl BatchSendArgs { } let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; // Resolve `--tempo.lane ` against the lanes file (default // `/tempo.lanes.toml`) and populate `tx.tempo.nonce_key` from the lane. diff --git a/crates/cast/src/cmd/erc20.rs b/crates/cast/src/cmd/erc20.rs index d68bb21a4acf8..3fd77c32155a3 100644 --- a/crates/cast/src/cmd/erc20.rs +++ b/crates/cast/src/cmd/erc20.rs @@ -3,6 +3,7 @@ use std::{str::FromStr, time::Duration}; use crate::{ cmd::send::{cast_send, cast_send_with_access_key}, format_uint_exp, tempo, + tempo::tempo_provider, tx::{CastTxSender, SendTxOpts, TxParams, fill_transaction_gas_fees}, }; use alloy_consensus::{SignableTransaction, Signed}; @@ -376,8 +377,7 @@ impl Erc20Subcommand { let mut tx_opts = $tx_opts; tempo::ensure_session_not_browser(&tx_opts.tempo, $send_tx.browser.browser)?; let (pre_resolved_signer, tempo_keychain) = if has_session { - let $provider = - ProviderBuilder::::from_config(&config)?.build()?; + let $provider = tempo_provider(&config)?; let chain = get_chain(config.chain, &$provider).await?; tempo::resolve_session_or_wallet_signer( &tx_opts.tempo, @@ -403,8 +403,7 @@ impl Erc20Subcommand { let signer = pre_resolved_signer .as_ref() .ok_or_else(|| eyre::eyre!("signer required for access key"))?; - let $provider = - ProviderBuilder::::from_config(&config)?.build()?; + let $provider = tempo_provider(&config)?; let $erc20 = IERC20::new($token.resolve(&$provider).await?, &$provider); let mut tx = { $build_tx }.into_transaction_request(); let chain = get_chain(config.chain, &$provider).await?; diff --git a/crates/cast/src/cmd/keychain.rs b/crates/cast/src/cmd/keychain.rs index 308b6324b59bf..9dbda9e6c9b07 100644 --- a/crates/cast/src/cmd/keychain.rs +++ b/crates/cast/src/cmd/keychain.rs @@ -1,3 +1,4 @@ +use crate::tempo::tempo_provider; use alloy_consensus::BlockHeader; use alloy_ens::NameOrAddress; use foundry_wallets::BrowserWalletOpts; @@ -20,9 +21,7 @@ use foundry_cli::{ utils::{LoadConfig, maybe_print_resolved_lane, parse_fee_token_address, resolve_lane}, }; use foundry_common::{ - FoundryTransactionBuilder, - provider::ProviderBuilder, - sh_warn, shell, + FoundryTransactionBuilder, sh_warn, shell, tempo::{ self, KeyType, KeysFile, TEMPO_BROWSER_GAS_BUFFER, WalletType, maybe_print_fee_token, read_tempo_keys_file, resolve_and_set_fee_token, tempo_keys_path, @@ -966,7 +965,7 @@ async fn run_inspect( ) -> Result<()> { let metadata = resolve_key_metadata(key_address, root_account)?; let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let info: KeyInfo = provider.get_keychain_key(metadata.root_account, key_address).await?; let provisioned = info.keyId != Address::ZERO; @@ -1088,7 +1087,7 @@ async fn run_inspect( /// `cast keychain check` / `cast keychain info` — query on-chain key status. async fn run_check(wallet_address: Address, key_address: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let info: KeyInfo = provider.get_keychain_key(wallet_address, key_address).await?; @@ -1380,9 +1379,7 @@ async fn run_doctor( return finalize_doctor(steps, context); } }; - let provider = match ProviderBuilder::::from_config(&config) - .and_then(|builder| builder.build()) - { + let provider = match tempo_provider(&config) { Ok(p) => p, Err(err) => { steps.push(DoctorStep::fail( @@ -2797,13 +2794,16 @@ async fn run_authorize( let enforce = enforce_limits || !limits.is_empty(); let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; // T6 admin keys are key-management only and use a dedicated precompile entrypoint. if admin { - if !is_tempo_hardfork_active(&provider, TempoHardfork::T6).await? { - eyre::bail!("--admin requires a Tempo T6-capable AccountKeychain RPC"); - } + ensure_tempo_hardfork( + &provider, + TempoHardfork::T6, + "--admin requires a Tempo T6-capable AccountKeychain RPC", + ) + .await?; // u64::MAX is the no-expiry default; anything else is an explicit expiry admin keys reject. eyre::ensure!(expiry == u64::MAX, "--admin cannot be combined with an explicit --expiry"); eyre::ensure!( @@ -2827,8 +2827,13 @@ async fn run_authorize( } let is_t3 = is_tempo_hardfork_active(&provider, TempoHardfork::T3).await?; - if witness.is_some() && !is_tempo_hardfork_active(&provider, TempoHardfork::T5).await? { - eyre::bail!("--witness requires a Tempo T5-capable AccountKeychain RPC"); + if witness.is_some() { + ensure_tempo_hardfork( + &provider, + TempoHardfork::T5, + "--witness requires a Tempo T5-capable AccountKeychain RPC", + ) + .await?; } let calldata = if is_t3 { @@ -3226,10 +3231,13 @@ async fn run_burn_witness( send_tx: SendTxOpts, ) -> Result<()> { let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; - if !is_tempo_hardfork_active(&provider, TempoHardfork::T5).await? { - eyre::bail!("burn-witness requires a Tempo T5-capable AccountKeychain RPC"); - } + let provider = tempo_provider(&config)?; + ensure_tempo_hardfork( + &provider, + TempoHardfork::T5, + "burn-witness requires a Tempo T5-capable AccountKeychain RPC", + ) + .await?; let calldata = IAccountKeychain::burnKeyAuthorizationWitnessCall { witness }.abi_encode(); send_keychain_tx(calldata, tx_opts, &send_tx, None).await?; @@ -3239,10 +3247,13 @@ async fn run_burn_witness( /// `cast keychain is-witness-burned` — check TIP-1053 witness burn state. async fn run_is_witness_burned(account: Address, witness: B256, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; - if !is_tempo_hardfork_active(&provider, TempoHardfork::T5).await? { - eyre::bail!("is-witness-burned requires a Tempo T5-capable AccountKeychain RPC"); - } + let provider = tempo_provider(&config)?; + ensure_tempo_hardfork( + &provider, + TempoHardfork::T5, + "is-witness-burned requires a Tempo T5-capable AccountKeychain RPC", + ) + .await?; let burned = provider .account_keychain() @@ -3267,10 +3278,13 @@ async fn run_is_witness_burned(account: Address, witness: B256, rpc: RpcOpts) -> /// `cast keychain is-admin` — check whether a key is the root or an active admin key (T6). async fn run_is_admin(account: Address, key_address: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; - if !is_tempo_hardfork_active(&provider, TempoHardfork::T6).await? { - eyre::bail!("is-admin requires a Tempo T6-capable AccountKeychain RPC"); - } + let provider = tempo_provider(&config)?; + ensure_tempo_hardfork( + &provider, + TempoHardfork::T6, + "is-admin requires a Tempo T6-capable AccountKeychain RPC", + ) + .await?; let is_admin = provider.account_keychain().isAdminKey(account, key_address).call().await?; @@ -3297,11 +3311,14 @@ async fn run_verify_keychain( admin: bool, ) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let command = if admin { "verify-admin" } else { "verify" }; - if !is_tempo_hardfork_active(&provider, TempoHardfork::T6).await? { - eyre::bail!("{command} requires a Tempo T6-capable SignatureVerifier RPC"); - } + ensure_tempo_hardfork( + &provider, + TempoHardfork::T6, + &format!("{command} requires a Tempo T6-capable SignatureVerifier RPC"), + ) + .await?; let verifier = ISignatureVerifier::new(SIGNATURE_VERIFIER_ADDRESS, &provider); let valid = if admin { @@ -3334,7 +3351,7 @@ async fn run_remaining_limit( rpc: RpcOpts, ) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let remaining: U256 = if is_tempo_hardfork_active(&provider, TempoHardfork::T3).await? { provider.get_keychain_remaining_limit(wallet_address, key_address, token).await? @@ -3412,11 +3429,14 @@ async fn run_policy_add_call( ) -> Result<()> { let metadata = resolve_key_metadata(key_address, root_account)?; let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; - if !is_tempo_hardfork_active(&provider, TempoHardfork::T3).await? { - eyre::bail!("allowed-call policy editing requires the Tempo T3 hardfork"); - } + ensure_tempo_hardfork( + &provider, + TempoHardfork::T3, + "allowed-call policy editing requires the Tempo T3 hardfork", + ) + .await?; let allowed = provider .account_keychain() @@ -3573,7 +3593,7 @@ pub(crate) async fn send_keychain_tx_with_root_signer( let config = send_tx.eth.load_config()?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; if let Some(interval) = send_tx.poll_interval { provider.client().set_poll_interval(Duration::from_secs(interval)); @@ -3752,6 +3772,43 @@ where } } +/// Fails early with `requirement` when `hardfork` is not active on the target network. +pub(crate) async fn ensure_tempo_hardfork

( + provider: &P, + hardfork: TempoHardfork, + requirement: &str, +) -> Result<()> +where + P: Provider, +{ + if !is_tempo_hardfork_active(provider, hardfork).await? { + eyre::bail!("{requirement}"); + } + Ok(()) +} + +/// Fails early with `requirement` when a Tempo precompile is not active yet: a pre-fork call +/// would succeed as a silent no-op instead of reverting. Prefers the hardfork query and falls +/// back to checking the precompile's code when the RPC lacks the method. +pub(crate) async fn ensure_tempo_precompile_active

( + provider: &P, + hardfork: TempoHardfork, + precompile: Address, + requirement: &str, +) -> Result<()> +where + P: Provider, +{ + let active = match is_tempo_hardfork_active(provider, hardfork).await { + Ok(active) => active, + Err(_) => !provider.get_code_at(precompile).await?.is_empty(), + }; + if !active { + eyre::bail!("{requirement}"); + } + Ok(()) +} + async fn anvil_tempo_hardfork_active

( provider: &P, hardfork: TempoHardfork, diff --git a/crates/cast/src/cmd/receive_policy.rs b/crates/cast/src/cmd/receive_policy.rs index 0b58a292e0770..6f0b39d10eb9b 100644 --- a/crates/cast/src/cmd/receive_policy.rs +++ b/crates/cast/src/cmd/receive_policy.rs @@ -1,8 +1,9 @@ use crate::{ cmd::{ - keychain::is_tempo_hardfork_active, + keychain::ensure_tempo_precompile_active, tip20::{resolve_tip20_signer, send_tip20_transaction}, }, + tempo::{print_payload, tempo_provider}, tx::{SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; @@ -16,7 +17,7 @@ use foundry_cli::{ opts::RpcOpts, utils::{LoadConfig, get_provider}, }; -use foundry_common::{provider::ProviderBuilder, shell}; +use foundry_common::shell; use foundry_evm::hardfork::TempoHardfork; use foundry_evm_networks::TEMPO_PRECOMPILE_ADDRESSES; use serde_json::{Value, json}; @@ -399,22 +400,19 @@ async fn ensure_receive_policy_t6

(provider: &P, command: &str) -> Result<()> where P: Provider, { - // Prefer the hardfork query, but if it is unavailable (e.g. an older RPC without the method) - // fall back to checking whether the guard precompile has code. - let active = match is_tempo_hardfork_active(provider, TempoHardfork::T6).await { - Ok(active) => active, - Err(_) => !provider.get_code_at(RECEIVE_POLICY_GUARD_ADDRESS).await?.is_empty(), - }; - if !active { - eyre::bail!("{command} requires a Tempo T6-capable ReceivePolicy RPC"); - } - Ok(()) + ensure_tempo_precompile_active( + provider, + TempoHardfork::T6, + RECEIVE_POLICY_GUARD_ADDRESS, + &format!("{command} requires a Tempo T6-capable ReceivePolicy RPC"), + ) + .await } async fn burn_receipt(receipt: Bytes, send_tx: SendTxOpts, tx: TxParams) -> Result<()> { decode_claim_receipt(&receipt)?; let config = send_tx.eth.rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; ensure_receive_policy_t6(&provider, "cast receive-policy receipt burn").await?; let (signer, access_key) = resolve_tip20_signer(&send_tx, &tx).await?; send_tip20_transaction( @@ -432,7 +430,7 @@ async fn burn_receipt(receipt: Bytes, send_tx: SendTxOpts, tx: TxParams) -> Resu async fn claim(to: NameOrAddress, receipt: Bytes, send_tx: SendTxOpts, tx: TxParams) -> Result<()> { decode_claim_receipt(&receipt)?; let config = send_tx.eth.rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; ensure_receive_policy_t6(&provider, "cast receive-policy claim").await?; let to = to.resolve(&provider).await?; let (signer, access_key) = resolve_tip20_signer(&send_tx, &tx).await?; @@ -624,18 +622,6 @@ fn print_claim_hint(payload: &Value) -> Result<()> { } } -fn print_payload(payload: Value, human: F) -> Result<()> -where - F: FnOnce(&Value) -> Result<()>, -{ - if shell::is_json() { - print_json_success(payload)?; - } else { - human(&payload)?; - } - Ok(()) -} - fn recovery_mode(recovery_authority: Address) -> &'static str { if recovery_authority == Address::ZERO { "originator" } else { "authority" } } diff --git a/crates/cast/src/cmd/storage_credits.rs b/crates/cast/src/cmd/storage_credits.rs index 58c3e7880c1f0..53260b451238c 100644 --- a/crates/cast/src/cmd/storage_credits.rs +++ b/crates/cast/src/cmd/storage_credits.rs @@ -1,17 +1,17 @@ use crate::{ cmd::{ - keychain::is_tempo_hardfork_active, + keychain::ensure_tempo_precompile_active, tip20::{resolve_tip20_signer, send_tip20_transaction}, }, + tempo::{print_payload, tempo_provider}, tx::{SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; use clap::{Parser, ValueEnum}; use eyre::Result; -use foundry_cli::{json::print_json_success, opts::RpcOpts, utils::LoadConfig}; -use foundry_common::{provider::ProviderBuilder, shell}; +use foundry_cli::{opts::RpcOpts, utils::LoadConfig}; use foundry_evm::hardfork::TempoHardfork; -use serde_json::{Value, json}; +use serde_json::json; use std::str::FromStr; use tempo_alloy::TempoNetwork; use tempo_contracts::precompiles::{IStorageCredits, STORAGE_CREDITS_ADDRESS}; @@ -116,7 +116,7 @@ impl StorageCreditsSubcommand { async fn balance(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; ensure_storage_credits_t7(&provider, "cast storage-credits balance").await?; let account = account.resolve(&provider).await?; @@ -134,7 +134,7 @@ async fn balance(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { async fn mode(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; ensure_storage_credits_t7(&provider, "cast storage-credits mode").await?; let account = account.resolve(&provider).await?; @@ -152,7 +152,7 @@ async fn mode(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { async fn budget(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; ensure_storage_credits_t7(&provider, "cast storage-credits budget").await?; let account = account.resolve(&provider).await?; @@ -206,36 +206,23 @@ async fn ensure_storage_credits_t7

(provider: &P, command: &str) -> Result<()> where P: alloy_provider::Provider, { - let active = match is_tempo_hardfork_active(provider, TempoHardfork::T7).await { - Ok(active) => active, - Err(_) => !provider.get_code_at(STORAGE_CREDITS_ADDRESS).await?.is_empty(), - }; - if !active { - eyre::bail!("{command} requires a Tempo T7-capable StorageCredits RPC"); - } - Ok(()) + ensure_tempo_precompile_active( + provider, + TempoHardfork::T7, + STORAGE_CREDITS_ADDRESS, + &format!("{command} requires a Tempo T7-capable StorageCredits RPC"), + ) + .await } /// Gate a write command on T7 before signing: on pre-T7 the precompile address is an empty account, /// so a transaction to it would silently succeed as a no-op. async fn ensure_send_storage_credits_t7(send_tx: &SendTxOpts, command: &str) -> Result<()> { let config = send_tx.eth.rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; ensure_storage_credits_t7(&provider, command).await } -fn print_payload(payload: Value, human: F) -> Result<()> -where - F: FnOnce(&Value) -> Result<()>, -{ - if shell::is_json() { - print_json_success(payload)?; - } else { - human(&payload)?; - } - Ok(()) -} - impl CreditMode { const fn to_sol(self) -> IStorageCredits::Mode { match self { diff --git a/crates/cast/src/cmd/tip20/create.rs b/crates/cast/src/cmd/tip20/create.rs index ce1768f8b60bc..00c22c43c4ad1 100644 --- a/crates/cast/src/cmd/tip20/create.rs +++ b/crates/cast/src/cmd/tip20/create.rs @@ -1,6 +1,9 @@ #![allow(clippy::too_many_arguments)] -use crate::tx::{SendTxOpts, TxParams}; +use crate::{ + tempo::tempo_provider, + tx::{SendTxOpts, TxParams}, +}; use alloy_ens::NameOrAddress; use alloy_network::{Network, TransactionBuilder}; use alloy_primitives::B256; @@ -9,7 +12,6 @@ use alloy_rpc_types::TransactionInputKind; use alloy_sol_types::{SolCall, SolError}; use alloy_transport::{RpcError, TransportErrorKind}; use foundry_cli::utils::LoadConfig; -use foundry_common::provider::ProviderBuilder; use tempo_alloy::TempoNetwork; use tempo_contracts::precompiles::{ TIP20_FACTORY_ADDRESS, UnknownFunctionSelector, createTokenWithLogoCall, is_iso4217_currency, @@ -67,7 +69,7 @@ pub(super) async fn run( } } - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let quote_token_addr = quote_token.resolve(&provider).await?; let admin_addr = admin.resolve(&provider).await?; diff --git a/crates/cast/src/cmd/tip20/logo.rs b/crates/cast/src/cmd/tip20/logo.rs index c0f9f257b74fb..87b2873766eaa 100644 --- a/crates/cast/src/cmd/tip20/logo.rs +++ b/crates/cast/src/cmd/tip20/logo.rs @@ -1,11 +1,10 @@ -use crate::tx::{SendTxOpts, TxParams}; +use crate::{ + tempo::tempo_provider, + tx::{SendTxOpts, TxParams}, +}; use alloy_ens::NameOrAddress; use foundry_cli::utils::LoadConfig; -use foundry_common::{ - provider::ProviderBuilder, - tempo::{Tip20LogoUriValidationError, validate_tip20_logo_uri}, -}; -use tempo_alloy::TempoNetwork; +use foundry_common::tempo::{Tip20LogoUriValidationError, validate_tip20_logo_uri}; pub(super) fn check(logo_uri: String) -> eyre::Result<()> { validate_logo_uri(&logo_uri)?; @@ -24,7 +23,7 @@ pub(super) async fn set( let (signer, tempo_access_key) = super::resolve_tip20_signer(&send_tx, &tx_opts).await?; let config = send_tx.eth.rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let token_addr = token.resolve(&provider).await?; super::send_tip20_transaction( diff --git a/crates/cast/src/cmd/tip20/mine.rs b/crates/cast/src/cmd/tip20/mine.rs index 7dad07a5d14b9..92e343b77b238 100644 --- a/crates/cast/src/cmd/tip20/mine.rs +++ b/crates/cast/src/cmd/tip20/mine.rs @@ -4,13 +4,13 @@ use crate::{ send::{cast_send, cast_send_with_access_key}, }, tempo, + tempo::tempo_provider, tx::{SendTxOpts, TxParams, fill_transaction_gas_fees}, }; use alloy_primitives::{Address, B256, keccak256}; use alloy_signer::Signer; use eyre::Result; use foundry_cli::utils::{LoadConfig, get_chain}; -use foundry_common::provider::ProviderBuilder; use rand::{RngCore, SeedableRng, rngs::StdRng}; use std::time::{Duration, Instant}; use tempo_alloy::{ @@ -83,7 +83,7 @@ pub(super) async fn register( ) -> Result<()> { let config = send_tx.eth.load_config()?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let chain = get_chain(config.chain, &provider).await?; tempo::ensure_session_not_browser(&tx_opts.tempo, send_tx.browser.browser)?; let (signer, tempo_access_key) = diff --git a/crates/cast/src/cmd/tip20/mod.rs b/crates/cast/src/cmd/tip20/mod.rs index d8860b3d5cdd0..d0e213e051073 100644 --- a/crates/cast/src/cmd/tip20/mod.rs +++ b/crates/cast/src/cmd/tip20/mod.rs @@ -1,6 +1,7 @@ use crate::{ cmd::send::{cast_send, cast_send_with_access_key, validate_sponsor_url}, tempo, + tempo::tempo_provider, tx::{CastTxBuilder, CastTxSender, SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; @@ -16,7 +17,6 @@ use foundry_cli::{ }; use foundry_common::{ FoundryTransactionBuilder, - provider::ProviderBuilder, tempo::{TEMPO_BROWSER_GAS_BUFFER, maybe_print_fee_token, resolve_and_set_fee_token}, }; use foundry_wallets::{TempoAccessKeyConfig, WalletSigner}; @@ -191,7 +191,7 @@ pub(crate) async fn resolve_tip20_signer( tempo::ensure_session_not_browser(&tx_params.tempo, send_tx.browser.browser)?; let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let chain = get_chain(config.chain, &provider).await?; tempo::resolve_session_or_wallet_signer(&tx_params.tempo, &send_tx.eth.wallet, chain.id()).await } @@ -227,7 +227,7 @@ pub(crate) async fn send_tip20_transaction( } let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; if let Some(interval) = send_tx.poll_interval { provider.client().set_poll_interval(Duration::from_secs(interval)) } @@ -290,14 +290,14 @@ pub(crate) async fn send_tip20_transaction( tx.set_gas_limit(gas + TEMPO_BROWSER_GAS_BUFFER); } if let Some(sponsor) = &tempo_sponsor { - sponsor - .resolve_and_set_fee_token( - (!config.eth_rpc_curl).then_some(&provider), - Some(chain), - &mut tx, - ) - .await?; - sponsor.attach_and_print::(&mut tx, browser.address()).await?; + attach_sponsor( + sponsor, + (!config.eth_rpc_curl).then_some(&provider), + chain, + &mut tx, + browser.address(), + ) + .await?; } else { let fee_token = resolve_and_set_fee_token( (!config.eth_rpc_curl).then_some(&provider), @@ -319,14 +319,14 @@ pub(crate) async fn send_tip20_transaction( let (mut tx, _) = builder.build_with_access_key(ak.wallet_address, &ak).await?; maybe_print_resolved_lane(resolved_lane.as_ref(), tx.nonce().unwrap_or_default())?; if let Some(sponsor) = &tempo_sponsor { - sponsor - .resolve_and_set_fee_token( - (!config.eth_rpc_curl).then_some(&provider), - Some(chain), - &mut tx, - ) - .await?; - sponsor.attach_and_print::(&mut tx, ak.wallet_address).await?; + attach_sponsor( + sponsor, + (!config.eth_rpc_curl).then_some(&provider), + chain, + &mut tx, + ak.wallet_address, + ) + .await?; } cast_send_with_access_key( &provider, @@ -342,12 +342,7 @@ pub(crate) async fn send_tip20_transaction( ) .await?; } else if let Some(sponsor_url) = sponsor_url { - let signer = match pre_resolved_signer { - Some(signer) => signer, - None => send_tx.eth.wallet.signer().await?, - }; - let from = signer.address(); - crate::tx::validate_from_address(send_tx.eth.wallet.from, from)?; + let (signer, _) = resolve_send_signer(pre_resolved_signer, &send_tx.eth).await?; let (mut tx, _) = builder.build(&signer).await?; maybe_print_resolved_lane(resolved_lane.as_ref(), tx.nonce().unwrap_or_default())?; @@ -376,24 +371,19 @@ pub(crate) async fn send_tip20_transaction( ) .await?; } else { - let signer = match pre_resolved_signer { - Some(signer) => signer, - None => send_tx.eth.wallet.signer().await?, - }; - let from = signer.address(); - crate::tx::validate_from_address(send_tx.eth.wallet.from, from)?; + let (signer, from) = resolve_send_signer(pre_resolved_signer, &send_tx.eth).await?; let (mut tx, _) = builder.build(&signer).await?; maybe_print_resolved_lane(resolved_lane.as_ref(), tx.nonce().unwrap_or_default())?; if let Some(sponsor) = &tempo_sponsor { - sponsor - .resolve_and_set_fee_token( - (!config.eth_rpc_curl).then_some(&provider), - Some(chain), - &mut tx, - ) - .await?; - sponsor.attach_and_print::(&mut tx, from).await?; + attach_sponsor( + sponsor, + (!config.eth_rpc_curl).then_some(&provider), + chain, + &mut tx, + from, + ) + .await?; } let wallet = EthereumWallet::from(signer); @@ -417,6 +407,43 @@ pub(crate) async fn send_tip20_transaction( Ok(()) } +/// Resolves the sending signer, falling back to the wallet options, and validates it against +/// an explicit `--from`. +async fn resolve_send_signer( + pre_resolved: Option, + eth: &foundry_cli::opts::EthereumOpts, +) -> eyre::Result<(WalletSigner, Address)> { + let signer = match pre_resolved { + Some(signer) => signer, + None => eth.wallet.signer().await?, + }; + let from = signer.address(); + crate::tx::validate_from_address(eth.wallet.from, from)?; + Ok((signer, from)) +} + +/// Resolves the sponsored fee token and attaches the sponsor signature preview for `payer`. +async fn attach_sponsor

( + sponsor: &crate::tempo::TempoSponsor, + provider: Option<&P>, + chain: foundry_config::Chain, + tx: &mut ::TransactionRequest, + payer: Address, +) -> eyre::Result<()> +where + P: Provider, +{ + sponsor + .resolve_and_set_fee_token( + provider.map(|p| p as &dyn Provider), + Some(chain), + tx, + ) + .await?; + sponsor.attach_and_print::(tx, payer).await?; + Ok(()) +} + impl TxParams { fn into_transaction_opts(self) -> TransactionOpts { TransactionOpts { diff --git a/crates/cast/src/cmd/tip403.rs b/crates/cast/src/cmd/tip403.rs index 1d61d3780d561..3af30ce81b0ce 100644 --- a/crates/cast/src/cmd/tip403.rs +++ b/crates/cast/src/cmd/tip403.rs @@ -1,5 +1,6 @@ use crate::{ cmd::tip20::{resolve_tip20_signer, send_tip20_transaction}, + tempo::print_payload, tx::{SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; @@ -7,12 +8,10 @@ use alloy_primitives::Address; use clap::{Parser, ValueEnum}; use eyre::Result; use foundry_cli::{ - json::print_json_success, opts::RpcOpts, utils::{LoadConfig, get_provider}, }; -use foundry_common::shell; -use serde_json::{Value, json}; +use serde_json::json; use std::str::FromStr; use tempo_contracts::precompiles::{ITIP403Registry, TIP403_REGISTRY_ADDRESS}; use tempo_primitives::TempoAddressExt; @@ -307,18 +306,6 @@ fn address_array(accounts: &[Address]) -> String { format!("[{}]", accounts.iter().map(Address::to_string).collect::>().join(",")) } -fn print_payload(payload: Value, human: F) -> Result<()> -where - F: FnOnce(&Value) -> Result<()>, -{ - if shell::is_json() { - print_json_success(payload)?; - } else { - human(&payload)?; - } - Ok(()) -} - impl PolicyKind { const fn to_sol(self) -> ITIP403Registry::PolicyType { match self { diff --git a/crates/cast/src/cmd/vaddr/create.rs b/crates/cast/src/cmd/vaddr/create.rs index 7b786b53dcaea..bfcee127b8a89 100644 --- a/crates/cast/src/cmd/vaddr/create.rs +++ b/crates/cast/src/cmd/vaddr/create.rs @@ -5,6 +5,7 @@ use crate::{ tip20::mine, }, tempo, + tempo::tempo_provider, tx::{CastTxSender, SendTxOpts, TxParams, fill_transaction_gas_fees}, }; use alloy_network::Network; @@ -19,7 +20,6 @@ use foundry_cli::{ use foundry_common::{ FoundryTransactionBuilder, fmt::{UIfmt, UIfmtReceiptExt}, - provider::ProviderBuilder, shell, tempo::{maybe_print_fee_token, resolve_and_set_fee_token}, }; @@ -157,7 +157,7 @@ async fn register( ) -> Result { let config = send_tx.eth.load_config()?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let chain = get_chain(config.chain, &provider).await?; tempo::ensure_session_not_browser(&tx_opts.tempo, send_tx.browser.browser)?; let (signer, tempo_access_key) = diff --git a/crates/cast/src/cmd/vaddr/resolve.rs b/crates/cast/src/cmd/vaddr/resolve.rs index 96936f4fe4713..e069ab99e1656 100644 --- a/crates/cast/src/cmd/vaddr/resolve.rs +++ b/crates/cast/src/cmd/vaddr/resolve.rs @@ -1,16 +1,14 @@ +use crate::tempo::tempo_provider; use alloy_primitives::{Address, hex}; use eyre::Result; use foundry_cli::{opts::RpcOpts, utils::LoadConfig}; -use foundry_common::{provider::ProviderBuilder, shell}; +use foundry_common::shell; use serde_json::json; -use tempo_alloy::{ - TempoNetwork, - contracts::precompiles::{ADDRESS_REGISTRY_ADDRESS, IAddressRegistry}, -}; +use tempo_alloy::contracts::precompiles::{ADDRESS_REGISTRY_ADDRESS, IAddressRegistry}; pub(super) async fn run(addr: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let registry = IAddressRegistry::new(ADDRESS_REGISTRY_ADDRESS, &provider); let decode_builder = registry.decodeVirtualAddress(addr); diff --git a/crates/cast/src/cmd/vaddr/watch.rs b/crates/cast/src/cmd/vaddr/watch.rs index 966f6ea247e64..74b7aa7fc1a17 100644 --- a/crates/cast/src/cmd/vaddr/watch.rs +++ b/crates/cast/src/cmd/vaddr/watch.rs @@ -1,12 +1,12 @@ +use crate::tempo::tempo_provider; use alloy_primitives::{Address, B256, keccak256}; use alloy_provider::Provider; use alloy_rpc_types::{BlockNumberOrTag, Filter}; use eyre::Result; use foundry_cli::{opts::RpcOpts, utils::LoadConfig}; -use foundry_common::{provider::ProviderBuilder, shell}; +use foundry_common::shell; use serde_json::json; use std::sync::LazyLock; -use tempo_alloy::TempoNetwork; use tempo_primitives::TempoAddressExt; static TRANSFER_TOPIC: LazyLock = @@ -23,7 +23,7 @@ pub(super) async fn run( } let config = rpc.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; // Transfer(address indexed from, address indexed to, uint256 value) // topic[0] = event sig, topic[1] = from, topic[2] = to diff --git a/crates/cast/src/cmd/wallet/session.rs b/crates/cast/src/cmd/wallet/session.rs index 78b625a2e5899..fc51f98516c0d 100644 --- a/crates/cast/src/cmd/wallet/session.rs +++ b/crates/cast/src/cmd/wallet/session.rs @@ -1,3 +1,4 @@ +use crate::tempo::tempo_provider; use alloy_primitives::{Address, B256, U256}; use alloy_provider::Provider; use alloy_signer::Signer; @@ -9,7 +10,6 @@ use foundry_cli::{ utils::{LoadConfig, parse_fee_token_address}, }; use foundry_common::{ - provider::ProviderBuilder, sh_println, shell, tempo::{ GeneratedSessionKey, SessionAuthorizationRequest, SessionEntry, SessionSpendLimit, @@ -395,7 +395,7 @@ async fn resolve_session_chain_id(send_tx: &SendTxOpts) -> Result { return Ok(chain.id()); } - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; provider.get_chain_id().await.wrap_err( "failed to resolve session chain id from RPC; pass --chain/--chain-id or --rpc-url", ) @@ -585,7 +585,7 @@ async fn run_revoke_with_policy( } let config = send_tx.eth.load_config()?; - let provider = ProviderBuilder::::from_config(&config)?.build()?; + let provider = tempo_provider(&config)?; let rpc_chain_id = provider.get_chain_id().await?; if rpc_chain_id != entry.chain_id { eyre::bail!( @@ -1067,8 +1067,7 @@ mod tests { let mut send_tx = empty_send_tx_opts(); send_tx.eth.rpc.common.rpc_url = Some("http://127.0.0.1:9".to_string()); let config = send_tx.eth.load_config().unwrap(); - let provider = - ProviderBuilder::::from_config(&config).unwrap().build().unwrap(); + let provider = crate::tempo::tempo_provider(&config).unwrap(); handle_revoke_error( &provider, session_id, @@ -1104,8 +1103,7 @@ mod tests { let mut send_tx = empty_send_tx_opts(); send_tx.eth.rpc.common.rpc_url = Some("http://127.0.0.1:9".to_string()); let config = send_tx.eth.load_config().unwrap(); - let provider = - ProviderBuilder::::from_config(&config).unwrap().build().unwrap(); + let provider = crate::tempo::tempo_provider(&config).unwrap(); handle_revoke_error(&provider, session_id, &entry).await; let session = read_session_entry(session_id).unwrap().unwrap(); diff --git a/crates/cast/src/tempo.rs b/crates/cast/src/tempo.rs index 011532d1c8fb8..9a41d4b45d4cc 100644 --- a/crates/cast/src/tempo.rs +++ b/crates/cast/src/tempo.rs @@ -4,14 +4,37 @@ use crate::tx::fill_transaction_gas_fees; use alloy_network::{Network, TransactionBuilder}; use alloy_provider::Provider; use eyre::Result; -use foundry_cli::opts::TempoOpts; -use foundry_common::FoundryTransactionBuilder; -use foundry_config::{Chain, Eip1559FeeEstimatePreset}; +use foundry_cli::{json::print_json_success, opts::TempoOpts}; +use foundry_common::{ + FoundryTransactionBuilder, + provider::{ProviderBuilder, RetryProvider}, + shell, +}; +use foundry_config::{Chain, Config, Eip1559FeeEstimatePreset}; use foundry_wallets::{TempoAccessKeyConfig, WalletOpts, WalletSigner}; +use serde_json::Value; use tempo_alloy::TempoNetwork; pub use foundry_common::tempo::{TempoSponsor, TempoSponsorPreview, resolve_tempo_sponsor_signer}; +/// Builds the Tempo network provider from a loaded config. +pub(crate) fn tempo_provider(config: &Config) -> Result> { + ProviderBuilder::::from_config(config)?.build() +} + +/// Prints a command result: the raw payload in JSON mode, the human rendering otherwise. +pub(crate) fn print_payload(payload: Value, human: F) -> Result<()> +where + F: FnOnce(&Value) -> Result<()>, +{ + if shell::is_json() { + print_json_success(payload)?; + } else { + human(&payload)?; + } + Ok(()) +} + pub(crate) fn print_expires(expires_at: Option) -> Result<()> { if let Some(ts) = expires_at { sh_status!("Transaction expires at unix timestamp {ts}")?; From ea3ef9c466af9b2d5df7983cd177e39820ec3304 Mon Sep 17 00:00:00 2001 From: 0xMars42 <195151467+0xMars42@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:35:16 +0200 Subject: [PATCH 2/3] review: drop the tempo_provider helper Restore the inline provider construction at its call sites, including the doctor error-matching variant and the session tests. The call sites are back to what master has. --- crates/cast/src/args.rs | 7 ++++--- crates/cast/src/cmd/batch_mktx.rs | 4 ++-- crates/cast/src/cmd/batch_send.rs | 4 ++-- crates/cast/src/cmd/erc20.rs | 7 ++++--- crates/cast/src/cmd/keychain.rs | 29 ++++++++++++++------------ crates/cast/src/cmd/receive_policy.rs | 8 +++---- crates/cast/src/cmd/storage_credits.rs | 11 +++++----- crates/cast/src/cmd/tip20/create.rs | 8 +++---- crates/cast/src/cmd/tip20/logo.rs | 13 ++++++------ crates/cast/src/cmd/tip20/mine.rs | 4 ++-- crates/cast/src/cmd/tip20/mod.rs | 6 +++--- crates/cast/src/cmd/vaddr/create.rs | 4 ++-- crates/cast/src/cmd/vaddr/resolve.rs | 10 +++++---- crates/cast/src/cmd/vaddr/watch.rs | 6 +++--- crates/cast/src/cmd/wallet/session.rs | 12 ++++++----- crates/cast/src/tempo.rs | 13 ++---------- 16 files changed, 73 insertions(+), 73 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 040de3081cfd9..4a8b6f3ff3ef1 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -2,7 +2,6 @@ use crate::{ Cast, SimpleCast, cmd::erc20::IERC20, opts::{Cast as CastArgs, CastSubcommand, ToBaseArgs}, - tempo::tempo_provider, traces::identifier::SignaturesIdentifier, tx::CastTxSender, }; @@ -423,7 +422,8 @@ pub async fn run_command(args: CastArgs) -> Result<()> { .await? } Some(NetworkVariant::Tempo) => { - let provider = tempo_provider(&config)?; + let provider = + ProviderBuilder::::from_config(&config)?.build()?; Cast::new(&provider) .block_raw(block.unwrap_or(BlockId::Number(Latest)), full) .await? @@ -729,7 +729,8 @@ pub async fn run_command(args: CastArgs) -> Result<()> { .await? } Some(NetworkVariant::Tempo) => { - let provider = tempo_provider(&config)?; + let provider = + ProviderBuilder::::from_config(&config)?.build()?; Cast::new(&provider) .transaction(tx_hash, from, nonce, field, is_raw, to_request, lane) .await? diff --git a/crates/cast/src/cmd/batch_mktx.rs b/crates/cast/src/cmd/batch_mktx.rs index 1fc50470c012d..235244b289dbc 100644 --- a/crates/cast/src/cmd/batch_mktx.rs +++ b/crates/cast/src/cmd/batch_mktx.rs @@ -6,7 +6,6 @@ use crate::{ call_spec::CallSpec, tempo, - tempo::tempo_provider, tx::{self, CastTxBuilder}, }; use alloy_consensus::SignableTransaction; @@ -23,6 +22,7 @@ use foundry_cli::{ }; use foundry_common::{ FoundryTransactionBuilder, + provider::ProviderBuilder, tempo::{maybe_print_fee_token, resolve_and_set_fee_token}, }; use foundry_wallets::{TempoAccessKeyConfig, WalletOpts, WalletSigner}; @@ -76,7 +76,7 @@ impl BatchMakeTxArgs { } let config = eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; // Resolve `--tempo.lane ` against the lanes file (default // `/tempo.lanes.toml`) and populate `tx.tempo.nonce_key` from the lane. diff --git a/crates/cast/src/cmd/batch_send.rs b/crates/cast/src/cmd/batch_send.rs index 6f9529458e6c2..af9d359a52721 100644 --- a/crates/cast/src/cmd/batch_send.rs +++ b/crates/cast/src/cmd/batch_send.rs @@ -8,7 +8,6 @@ use crate::{ call_spec::CallSpec, cmd::send::{cast_send, cast_send_with_access_key}, tempo, - tempo::tempo_provider, tx::{self, CastTxBuilder, SendTxOpts}, }; use alloy_network::{EthereumWallet, TransactionBuilder}; @@ -20,6 +19,7 @@ use foundry_cli::{ opts::TransactionOpts, utils::{self, LoadConfig, maybe_print_resolved_lane, resolve_lane}, }; +use foundry_common::provider::ProviderBuilder; use std::time::Duration; use tempo_alloy::TempoNetwork; @@ -69,7 +69,7 @@ impl BatchSendArgs { } let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; // Resolve `--tempo.lane ` against the lanes file (default // `/tempo.lanes.toml`) and populate `tx.tempo.nonce_key` from the lane. diff --git a/crates/cast/src/cmd/erc20.rs b/crates/cast/src/cmd/erc20.rs index 3fd77c32155a3..d68bb21a4acf8 100644 --- a/crates/cast/src/cmd/erc20.rs +++ b/crates/cast/src/cmd/erc20.rs @@ -3,7 +3,6 @@ use std::{str::FromStr, time::Duration}; use crate::{ cmd::send::{cast_send, cast_send_with_access_key}, format_uint_exp, tempo, - tempo::tempo_provider, tx::{CastTxSender, SendTxOpts, TxParams, fill_transaction_gas_fees}, }; use alloy_consensus::{SignableTransaction, Signed}; @@ -377,7 +376,8 @@ impl Erc20Subcommand { let mut tx_opts = $tx_opts; tempo::ensure_session_not_browser(&tx_opts.tempo, $send_tx.browser.browser)?; let (pre_resolved_signer, tempo_keychain) = if has_session { - let $provider = tempo_provider(&config)?; + let $provider = + ProviderBuilder::::from_config(&config)?.build()?; let chain = get_chain(config.chain, &$provider).await?; tempo::resolve_session_or_wallet_signer( &tx_opts.tempo, @@ -403,7 +403,8 @@ impl Erc20Subcommand { let signer = pre_resolved_signer .as_ref() .ok_or_else(|| eyre::eyre!("signer required for access key"))?; - let $provider = tempo_provider(&config)?; + let $provider = + ProviderBuilder::::from_config(&config)?.build()?; let $erc20 = IERC20::new($token.resolve(&$provider).await?, &$provider); let mut tx = { $build_tx }.into_transaction_request(); let chain = get_chain(config.chain, &$provider).await?; diff --git a/crates/cast/src/cmd/keychain.rs b/crates/cast/src/cmd/keychain.rs index 9dbda9e6c9b07..a81437adb496b 100644 --- a/crates/cast/src/cmd/keychain.rs +++ b/crates/cast/src/cmd/keychain.rs @@ -1,4 +1,3 @@ -use crate::tempo::tempo_provider; use alloy_consensus::BlockHeader; use alloy_ens::NameOrAddress; use foundry_wallets::BrowserWalletOpts; @@ -21,7 +20,9 @@ use foundry_cli::{ utils::{LoadConfig, maybe_print_resolved_lane, parse_fee_token_address, resolve_lane}, }; use foundry_common::{ - FoundryTransactionBuilder, sh_warn, shell, + FoundryTransactionBuilder, + provider::ProviderBuilder, + sh_warn, shell, tempo::{ self, KeyType, KeysFile, TEMPO_BROWSER_GAS_BUFFER, WalletType, maybe_print_fee_token, read_tempo_keys_file, resolve_and_set_fee_token, tempo_keys_path, @@ -965,7 +966,7 @@ async fn run_inspect( ) -> Result<()> { let metadata = resolve_key_metadata(key_address, root_account)?; let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let info: KeyInfo = provider.get_keychain_key(metadata.root_account, key_address).await?; let provisioned = info.keyId != Address::ZERO; @@ -1087,7 +1088,7 @@ async fn run_inspect( /// `cast keychain check` / `cast keychain info` — query on-chain key status. async fn run_check(wallet_address: Address, key_address: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let info: KeyInfo = provider.get_keychain_key(wallet_address, key_address).await?; @@ -1379,7 +1380,9 @@ async fn run_doctor( return finalize_doctor(steps, context); } }; - let provider = match tempo_provider(&config) { + let provider = match ProviderBuilder::::from_config(&config) + .and_then(|builder| builder.build()) + { Ok(p) => p, Err(err) => { steps.push(DoctorStep::fail( @@ -2794,7 +2797,7 @@ async fn run_authorize( let enforce = enforce_limits || !limits.is_empty(); let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; // T6 admin keys are key-management only and use a dedicated precompile entrypoint. if admin { @@ -3231,7 +3234,7 @@ async fn run_burn_witness( send_tx: SendTxOpts, ) -> Result<()> { let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_tempo_hardfork( &provider, TempoHardfork::T5, @@ -3247,7 +3250,7 @@ async fn run_burn_witness( /// `cast keychain is-witness-burned` — check TIP-1053 witness burn state. async fn run_is_witness_burned(account: Address, witness: B256, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_tempo_hardfork( &provider, TempoHardfork::T5, @@ -3278,7 +3281,7 @@ async fn run_is_witness_burned(account: Address, witness: B256, rpc: RpcOpts) -> /// `cast keychain is-admin` — check whether a key is the root or an active admin key (T6). async fn run_is_admin(account: Address, key_address: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_tempo_hardfork( &provider, TempoHardfork::T6, @@ -3311,7 +3314,7 @@ async fn run_verify_keychain( admin: bool, ) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let command = if admin { "verify-admin" } else { "verify" }; ensure_tempo_hardfork( &provider, @@ -3351,7 +3354,7 @@ async fn run_remaining_limit( rpc: RpcOpts, ) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let remaining: U256 = if is_tempo_hardfork_active(&provider, TempoHardfork::T3).await? { provider.get_keychain_remaining_limit(wallet_address, key_address, token).await? @@ -3429,7 +3432,7 @@ async fn run_policy_add_call( ) -> Result<()> { let metadata = resolve_key_metadata(key_address, root_account)?; let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_tempo_hardfork( &provider, @@ -3593,7 +3596,7 @@ pub(crate) async fn send_keychain_tx_with_root_signer( let config = send_tx.eth.load_config()?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; if let Some(interval) = send_tx.poll_interval { provider.client().set_poll_interval(Duration::from_secs(interval)); diff --git a/crates/cast/src/cmd/receive_policy.rs b/crates/cast/src/cmd/receive_policy.rs index 6f0b39d10eb9b..d1d76bfe4e5aa 100644 --- a/crates/cast/src/cmd/receive_policy.rs +++ b/crates/cast/src/cmd/receive_policy.rs @@ -3,7 +3,7 @@ use crate::{ keychain::ensure_tempo_precompile_active, tip20::{resolve_tip20_signer, send_tip20_transaction}, }, - tempo::{print_payload, tempo_provider}, + tempo::print_payload, tx::{SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; @@ -17,7 +17,7 @@ use foundry_cli::{ opts::RpcOpts, utils::{LoadConfig, get_provider}, }; -use foundry_common::shell; +use foundry_common::{provider::ProviderBuilder, shell}; use foundry_evm::hardfork::TempoHardfork; use foundry_evm_networks::TEMPO_PRECOMPILE_ADDRESSES; use serde_json::{Value, json}; @@ -412,7 +412,7 @@ where async fn burn_receipt(receipt: Bytes, send_tx: SendTxOpts, tx: TxParams) -> Result<()> { decode_claim_receipt(&receipt)?; let config = send_tx.eth.rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_receive_policy_t6(&provider, "cast receive-policy receipt burn").await?; let (signer, access_key) = resolve_tip20_signer(&send_tx, &tx).await?; send_tip20_transaction( @@ -430,7 +430,7 @@ async fn burn_receipt(receipt: Bytes, send_tx: SendTxOpts, tx: TxParams) -> Resu async fn claim(to: NameOrAddress, receipt: Bytes, send_tx: SendTxOpts, tx: TxParams) -> Result<()> { decode_claim_receipt(&receipt)?; let config = send_tx.eth.rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_receive_policy_t6(&provider, "cast receive-policy claim").await?; let to = to.resolve(&provider).await?; let (signer, access_key) = resolve_tip20_signer(&send_tx, &tx).await?; diff --git a/crates/cast/src/cmd/storage_credits.rs b/crates/cast/src/cmd/storage_credits.rs index 53260b451238c..effc808b833d4 100644 --- a/crates/cast/src/cmd/storage_credits.rs +++ b/crates/cast/src/cmd/storage_credits.rs @@ -3,13 +3,14 @@ use crate::{ keychain::ensure_tempo_precompile_active, tip20::{resolve_tip20_signer, send_tip20_transaction}, }, - tempo::{print_payload, tempo_provider}, + tempo::print_payload, tx::{SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; use clap::{Parser, ValueEnum}; use eyre::Result; use foundry_cli::{opts::RpcOpts, utils::LoadConfig}; +use foundry_common::provider::ProviderBuilder; use foundry_evm::hardfork::TempoHardfork; use serde_json::json; use std::str::FromStr; @@ -116,7 +117,7 @@ impl StorageCreditsSubcommand { async fn balance(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_storage_credits_t7(&provider, "cast storage-credits balance").await?; let account = account.resolve(&provider).await?; @@ -134,7 +135,7 @@ async fn balance(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { async fn mode(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_storage_credits_t7(&provider, "cast storage-credits mode").await?; let account = account.resolve(&provider).await?; @@ -152,7 +153,7 @@ async fn mode(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { async fn budget(account: NameOrAddress, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_storage_credits_t7(&provider, "cast storage-credits budget").await?; let account = account.resolve(&provider).await?; @@ -219,7 +220,7 @@ where /// so a transaction to it would silently succeed as a no-op. async fn ensure_send_storage_credits_t7(send_tx: &SendTxOpts, command: &str) -> Result<()> { let config = send_tx.eth.rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; ensure_storage_credits_t7(&provider, command).await } diff --git a/crates/cast/src/cmd/tip20/create.rs b/crates/cast/src/cmd/tip20/create.rs index 00c22c43c4ad1..ce1768f8b60bc 100644 --- a/crates/cast/src/cmd/tip20/create.rs +++ b/crates/cast/src/cmd/tip20/create.rs @@ -1,9 +1,6 @@ #![allow(clippy::too_many_arguments)] -use crate::{ - tempo::tempo_provider, - tx::{SendTxOpts, TxParams}, -}; +use crate::tx::{SendTxOpts, TxParams}; use alloy_ens::NameOrAddress; use alloy_network::{Network, TransactionBuilder}; use alloy_primitives::B256; @@ -12,6 +9,7 @@ use alloy_rpc_types::TransactionInputKind; use alloy_sol_types::{SolCall, SolError}; use alloy_transport::{RpcError, TransportErrorKind}; use foundry_cli::utils::LoadConfig; +use foundry_common::provider::ProviderBuilder; use tempo_alloy::TempoNetwork; use tempo_contracts::precompiles::{ TIP20_FACTORY_ADDRESS, UnknownFunctionSelector, createTokenWithLogoCall, is_iso4217_currency, @@ -69,7 +67,7 @@ pub(super) async fn run( } } - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let quote_token_addr = quote_token.resolve(&provider).await?; let admin_addr = admin.resolve(&provider).await?; diff --git a/crates/cast/src/cmd/tip20/logo.rs b/crates/cast/src/cmd/tip20/logo.rs index 87b2873766eaa..c0f9f257b74fb 100644 --- a/crates/cast/src/cmd/tip20/logo.rs +++ b/crates/cast/src/cmd/tip20/logo.rs @@ -1,10 +1,11 @@ -use crate::{ - tempo::tempo_provider, - tx::{SendTxOpts, TxParams}, -}; +use crate::tx::{SendTxOpts, TxParams}; use alloy_ens::NameOrAddress; use foundry_cli::utils::LoadConfig; -use foundry_common::tempo::{Tip20LogoUriValidationError, validate_tip20_logo_uri}; +use foundry_common::{ + provider::ProviderBuilder, + tempo::{Tip20LogoUriValidationError, validate_tip20_logo_uri}, +}; +use tempo_alloy::TempoNetwork; pub(super) fn check(logo_uri: String) -> eyre::Result<()> { validate_logo_uri(&logo_uri)?; @@ -23,7 +24,7 @@ pub(super) async fn set( let (signer, tempo_access_key) = super::resolve_tip20_signer(&send_tx, &tx_opts).await?; let config = send_tx.eth.rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let token_addr = token.resolve(&provider).await?; super::send_tip20_transaction( diff --git a/crates/cast/src/cmd/tip20/mine.rs b/crates/cast/src/cmd/tip20/mine.rs index 92e343b77b238..7dad07a5d14b9 100644 --- a/crates/cast/src/cmd/tip20/mine.rs +++ b/crates/cast/src/cmd/tip20/mine.rs @@ -4,13 +4,13 @@ use crate::{ send::{cast_send, cast_send_with_access_key}, }, tempo, - tempo::tempo_provider, tx::{SendTxOpts, TxParams, fill_transaction_gas_fees}, }; use alloy_primitives::{Address, B256, keccak256}; use alloy_signer::Signer; use eyre::Result; use foundry_cli::utils::{LoadConfig, get_chain}; +use foundry_common::provider::ProviderBuilder; use rand::{RngCore, SeedableRng, rngs::StdRng}; use std::time::{Duration, Instant}; use tempo_alloy::{ @@ -83,7 +83,7 @@ pub(super) async fn register( ) -> Result<()> { let config = send_tx.eth.load_config()?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let chain = get_chain(config.chain, &provider).await?; tempo::ensure_session_not_browser(&tx_opts.tempo, send_tx.browser.browser)?; let (signer, tempo_access_key) = diff --git a/crates/cast/src/cmd/tip20/mod.rs b/crates/cast/src/cmd/tip20/mod.rs index d0e213e051073..c94f780dc726b 100644 --- a/crates/cast/src/cmd/tip20/mod.rs +++ b/crates/cast/src/cmd/tip20/mod.rs @@ -1,7 +1,6 @@ use crate::{ cmd::send::{cast_send, cast_send_with_access_key, validate_sponsor_url}, tempo, - tempo::tempo_provider, tx::{CastTxBuilder, CastTxSender, SendTxOpts, TxParams}, }; use alloy_ens::NameOrAddress; @@ -17,6 +16,7 @@ use foundry_cli::{ }; use foundry_common::{ FoundryTransactionBuilder, + provider::ProviderBuilder, tempo::{TEMPO_BROWSER_GAS_BUFFER, maybe_print_fee_token, resolve_and_set_fee_token}, }; use foundry_wallets::{TempoAccessKeyConfig, WalletSigner}; @@ -191,7 +191,7 @@ pub(crate) async fn resolve_tip20_signer( tempo::ensure_session_not_browser(&tx_params.tempo, send_tx.browser.browser)?; let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let chain = get_chain(config.chain, &provider).await?; tempo::resolve_session_or_wallet_signer(&tx_params.tempo, &send_tx.eth.wallet, chain.id()).await } @@ -227,7 +227,7 @@ pub(crate) async fn send_tip20_transaction( } let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; if let Some(interval) = send_tx.poll_interval { provider.client().set_poll_interval(Duration::from_secs(interval)) } diff --git a/crates/cast/src/cmd/vaddr/create.rs b/crates/cast/src/cmd/vaddr/create.rs index bfcee127b8a89..7b786b53dcaea 100644 --- a/crates/cast/src/cmd/vaddr/create.rs +++ b/crates/cast/src/cmd/vaddr/create.rs @@ -5,7 +5,6 @@ use crate::{ tip20::mine, }, tempo, - tempo::tempo_provider, tx::{CastTxSender, SendTxOpts, TxParams, fill_transaction_gas_fees}, }; use alloy_network::Network; @@ -20,6 +19,7 @@ use foundry_cli::{ use foundry_common::{ FoundryTransactionBuilder, fmt::{UIfmt, UIfmtReceiptExt}, + provider::ProviderBuilder, shell, tempo::{maybe_print_fee_token, resolve_and_set_fee_token}, }; @@ -157,7 +157,7 @@ async fn register( ) -> Result { let config = send_tx.eth.load_config()?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let chain = get_chain(config.chain, &provider).await?; tempo::ensure_session_not_browser(&tx_opts.tempo, send_tx.browser.browser)?; let (signer, tempo_access_key) = diff --git a/crates/cast/src/cmd/vaddr/resolve.rs b/crates/cast/src/cmd/vaddr/resolve.rs index e069ab99e1656..96936f4fe4713 100644 --- a/crates/cast/src/cmd/vaddr/resolve.rs +++ b/crates/cast/src/cmd/vaddr/resolve.rs @@ -1,14 +1,16 @@ -use crate::tempo::tempo_provider; use alloy_primitives::{Address, hex}; use eyre::Result; use foundry_cli::{opts::RpcOpts, utils::LoadConfig}; -use foundry_common::shell; +use foundry_common::{provider::ProviderBuilder, shell}; use serde_json::json; -use tempo_alloy::contracts::precompiles::{ADDRESS_REGISTRY_ADDRESS, IAddressRegistry}; +use tempo_alloy::{ + TempoNetwork, + contracts::precompiles::{ADDRESS_REGISTRY_ADDRESS, IAddressRegistry}, +}; pub(super) async fn run(addr: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let registry = IAddressRegistry::new(ADDRESS_REGISTRY_ADDRESS, &provider); let decode_builder = registry.decodeVirtualAddress(addr); diff --git a/crates/cast/src/cmd/vaddr/watch.rs b/crates/cast/src/cmd/vaddr/watch.rs index 74b7aa7fc1a17..966f6ea247e64 100644 --- a/crates/cast/src/cmd/vaddr/watch.rs +++ b/crates/cast/src/cmd/vaddr/watch.rs @@ -1,12 +1,12 @@ -use crate::tempo::tempo_provider; use alloy_primitives::{Address, B256, keccak256}; use alloy_provider::Provider; use alloy_rpc_types::{BlockNumberOrTag, Filter}; use eyre::Result; use foundry_cli::{opts::RpcOpts, utils::LoadConfig}; -use foundry_common::shell; +use foundry_common::{provider::ProviderBuilder, shell}; use serde_json::json; use std::sync::LazyLock; +use tempo_alloy::TempoNetwork; use tempo_primitives::TempoAddressExt; static TRANSFER_TOPIC: LazyLock = @@ -23,7 +23,7 @@ pub(super) async fn run( } let config = rpc.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; // Transfer(address indexed from, address indexed to, uint256 value) // topic[0] = event sig, topic[1] = from, topic[2] = to diff --git a/crates/cast/src/cmd/wallet/session.rs b/crates/cast/src/cmd/wallet/session.rs index fc51f98516c0d..78b625a2e5899 100644 --- a/crates/cast/src/cmd/wallet/session.rs +++ b/crates/cast/src/cmd/wallet/session.rs @@ -1,4 +1,3 @@ -use crate::tempo::tempo_provider; use alloy_primitives::{Address, B256, U256}; use alloy_provider::Provider; use alloy_signer::Signer; @@ -10,6 +9,7 @@ use foundry_cli::{ utils::{LoadConfig, parse_fee_token_address}, }; use foundry_common::{ + provider::ProviderBuilder, sh_println, shell, tempo::{ GeneratedSessionKey, SessionAuthorizationRequest, SessionEntry, SessionSpendLimit, @@ -395,7 +395,7 @@ async fn resolve_session_chain_id(send_tx: &SendTxOpts) -> Result { return Ok(chain.id()); } - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; provider.get_chain_id().await.wrap_err( "failed to resolve session chain id from RPC; pass --chain/--chain-id or --rpc-url", ) @@ -585,7 +585,7 @@ async fn run_revoke_with_policy( } let config = send_tx.eth.load_config()?; - let provider = tempo_provider(&config)?; + let provider = ProviderBuilder::::from_config(&config)?.build()?; let rpc_chain_id = provider.get_chain_id().await?; if rpc_chain_id != entry.chain_id { eyre::bail!( @@ -1067,7 +1067,8 @@ mod tests { let mut send_tx = empty_send_tx_opts(); send_tx.eth.rpc.common.rpc_url = Some("http://127.0.0.1:9".to_string()); let config = send_tx.eth.load_config().unwrap(); - let provider = crate::tempo::tempo_provider(&config).unwrap(); + let provider = + ProviderBuilder::::from_config(&config).unwrap().build().unwrap(); handle_revoke_error( &provider, session_id, @@ -1103,7 +1104,8 @@ mod tests { let mut send_tx = empty_send_tx_opts(); send_tx.eth.rpc.common.rpc_url = Some("http://127.0.0.1:9".to_string()); let config = send_tx.eth.load_config().unwrap(); - let provider = crate::tempo::tempo_provider(&config).unwrap(); + let provider = + ProviderBuilder::::from_config(&config).unwrap().build().unwrap(); handle_revoke_error(&provider, session_id, &entry).await; let session = read_session_entry(session_id).unwrap().unwrap(); diff --git a/crates/cast/src/tempo.rs b/crates/cast/src/tempo.rs index 9a41d4b45d4cc..223b8af2c6cea 100644 --- a/crates/cast/src/tempo.rs +++ b/crates/cast/src/tempo.rs @@ -5,23 +5,14 @@ use alloy_network::{Network, TransactionBuilder}; use alloy_provider::Provider; use eyre::Result; use foundry_cli::{json::print_json_success, opts::TempoOpts}; -use foundry_common::{ - FoundryTransactionBuilder, - provider::{ProviderBuilder, RetryProvider}, - shell, -}; -use foundry_config::{Chain, Config, Eip1559FeeEstimatePreset}; +use foundry_common::{FoundryTransactionBuilder, shell}; +use foundry_config::{Chain, Eip1559FeeEstimatePreset}; use foundry_wallets::{TempoAccessKeyConfig, WalletOpts, WalletSigner}; use serde_json::Value; use tempo_alloy::TempoNetwork; pub use foundry_common::tempo::{TempoSponsor, TempoSponsorPreview, resolve_tempo_sponsor_signer}; -/// Builds the Tempo network provider from a loaded config. -pub(crate) fn tempo_provider(config: &Config) -> Result> { - ProviderBuilder::::from_config(config)?.build() -} - /// Prints a command result: the raw payload in JSON mode, the human rendering otherwise. pub(crate) fn print_payload(payload: Value, human: F) -> Result<()> where From d0d6cb0c2b17951c9845b60e672f26c8b949cfd8 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Tue, 21 Jul 2026 17:35:14 +0200 Subject: [PATCH 3/3] chore: remove ensure_tempo_hardfork --- crates/cast/src/cmd/keychain.rs | 78 +++++++++------------------------ 1 file changed, 20 insertions(+), 58 deletions(-) diff --git a/crates/cast/src/cmd/keychain.rs b/crates/cast/src/cmd/keychain.rs index f3c682bd9db1b..45bd1b78730f7 100644 --- a/crates/cast/src/cmd/keychain.rs +++ b/crates/cast/src/cmd/keychain.rs @@ -2801,12 +2801,9 @@ async fn run_authorize( // T6 admin keys are key-management only and use a dedicated precompile entrypoint. if admin { - ensure_tempo_hardfork( - &provider, - TempoHardfork::T6, - "--admin requires a Tempo T6-capable AccountKeychain RPC", - ) - .await?; + if !is_tempo_hardfork_active(&provider, TempoHardfork::T6).await? { + eyre::bail!("--admin requires a Tempo T6-capable AccountKeychain RPC"); + } // u64::MAX is the no-expiry default; anything else is an explicit expiry admin keys reject. eyre::ensure!(expiry == u64::MAX, "--admin cannot be combined with an explicit --expiry"); eyre::ensure!( @@ -2830,13 +2827,8 @@ async fn run_authorize( } let is_t3 = is_tempo_hardfork_active(&provider, TempoHardfork::T3).await?; - if witness.is_some() { - ensure_tempo_hardfork( - &provider, - TempoHardfork::T5, - "--witness requires a Tempo T5-capable AccountKeychain RPC", - ) - .await?; + if witness.is_some() && !is_tempo_hardfork_active(&provider, TempoHardfork::T5).await? { + eyre::bail!("--witness requires a Tempo T5-capable AccountKeychain RPC"); } let calldata = if is_t3 { @@ -3241,12 +3233,9 @@ async fn run_burn_witness( ) -> Result<()> { let config = send_tx.eth.load_config()?; let provider = ProviderBuilder::::from_config(&config)?.build()?; - ensure_tempo_hardfork( - &provider, - TempoHardfork::T5, - "burn-witness requires a Tempo T5-capable AccountKeychain RPC", - ) - .await?; + if !is_tempo_hardfork_active(&provider, TempoHardfork::T5).await? { + eyre::bail!("burn-witness requires a Tempo T5-capable AccountKeychain RPC"); + } let calldata = IAccountKeychain::burnKeyAuthorizationWitnessCall { witness }.abi_encode(); send_keychain_tx(calldata, tx_opts, &send_tx, None).await?; @@ -3257,12 +3246,9 @@ async fn run_burn_witness( async fn run_is_witness_burned(account: Address, witness: B256, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; let provider = ProviderBuilder::::from_config(&config)?.build()?; - ensure_tempo_hardfork( - &provider, - TempoHardfork::T5, - "is-witness-burned requires a Tempo T5-capable AccountKeychain RPC", - ) - .await?; + if !is_tempo_hardfork_active(&provider, TempoHardfork::T5).await? { + eyre::bail!("is-witness-burned requires a Tempo T5-capable AccountKeychain RPC"); + } let burned = provider .account_keychain() @@ -3288,12 +3274,9 @@ async fn run_is_witness_burned(account: Address, witness: B256, rpc: RpcOpts) -> async fn run_is_admin(account: Address, key_address: Address, rpc: RpcOpts) -> Result<()> { let config = rpc.load_config()?; let provider = ProviderBuilder::::from_config(&config)?.build()?; - ensure_tempo_hardfork( - &provider, - TempoHardfork::T6, - "is-admin requires a Tempo T6-capable AccountKeychain RPC", - ) - .await?; + if !is_tempo_hardfork_active(&provider, TempoHardfork::T6).await? { + eyre::bail!("is-admin requires a Tempo T6-capable AccountKeychain RPC"); + } let is_admin = provider.account_keychain().isAdminKey(account, key_address).call().await?; @@ -3322,12 +3305,9 @@ async fn run_verify_keychain( let config = rpc.load_config()?; let provider = ProviderBuilder::::from_config(&config)?.build()?; let command = if admin { "verify-admin" } else { "verify" }; - ensure_tempo_hardfork( - &provider, - TempoHardfork::T6, - &format!("{command} requires a Tempo T6-capable SignatureVerifier RPC"), - ) - .await?; + if !is_tempo_hardfork_active(&provider, TempoHardfork::T6).await? { + eyre::bail!("{command} requires a Tempo T6-capable SignatureVerifier RPC"); + } let verifier = ISignatureVerifier::new(SIGNATURE_VERIFIER_ADDRESS, &provider); let valid = if admin { @@ -3440,12 +3420,9 @@ async fn run_policy_add_call( let config = send_tx.eth.load_config()?; let provider = ProviderBuilder::::from_config(&config)?.build()?; - ensure_tempo_hardfork( - &provider, - TempoHardfork::T3, - "allowed-call policy editing requires the Tempo T3 hardfork", - ) - .await?; + if !is_tempo_hardfork_active(&provider, TempoHardfork::T3).await? { + eyre::bail!("allowed-call policy editing requires the Tempo T3 hardfork"); + } let allowed = provider .account_keychain() @@ -3781,21 +3758,6 @@ where } } -/// Fails early with `requirement` when `hardfork` is not active on the target network. -pub(crate) async fn ensure_tempo_hardfork

( - provider: &P, - hardfork: TempoHardfork, - requirement: &str, -) -> Result<()> -where - P: Provider, -{ - if !is_tempo_hardfork_active(provider, hardfork).await? { - eyre::bail!("{requirement}"); - } - Ok(()) -} - /// Fails early with `requirement` when a Tempo precompile is not active yet: a pre-fork call /// would succeed as a silent no-op instead of reverting. Prefers the hardfork query and falls /// back to checking the precompile's code when the RPC lacks the method.