Skip to main content

cast/cmd/
tempo.rs

1use alloy_primitives::Address;
2use alloy_signer_local::PrivateKeySigner;
3use clap::Parser;
4use eyre::Result;
5use foundry_common::tempo::{EnsureAccessKeyConfig, decode_key_authorization, ensure_access_key};
6use tempo_alloy::accounts::TempoAccountsStore;
7use tempo_primitives::transaction::SignedKeyAuthorization;
8
9mod zone;
10
11/// Tempo-specific commands.
12#[derive(Debug, Parser)]
13pub struct TempoArgs {
14    #[command(subcommand)]
15    command: TempoSubcommand,
16}
17
18impl TempoArgs {
19    pub async fn run(self) -> Result<()> {
20        self.command.run().await
21    }
22}
23
24/// Tempo wallet and zone integration commands.
25#[derive(Debug, Parser)]
26#[allow(
27    clippy::large_enum_variant,
28    reason = "parsed once; retaining PrivateKeySigner keeps access-key input typed and redacted"
29)]
30pub enum TempoSubcommand {
31    /// Deposit into and withdraw from Tempo zones.
32    Zone(zone::ZoneArgs),
33
34    /// Authorize a new access key against your Tempo wallet via wallet.tempo.
35    ///
36    /// Persists the key to `$TEMPO_HOME/wallet/store.json` (default
37    /// `~/.tempo/wallet/store.json`). Also runs automatically on a 402 from a
38    /// Tempo RPC when no local key is configured.
39    ///
40    /// Env: `TEMPO_HOME`, `TEMPO_CLI_AUTH_URL` (override auth service).
41    Login {
42        /// Chain ID to authorize the key for. Defaults to Tempo mainnet (4217).
43        #[arg(long, default_value_t = 4217)]
44        chain_id: u64,
45
46        /// Print the authorization URL to stderr instead of opening a browser.
47        #[arg(long)]
48        no_browser: bool,
49    },
50
51    /// Import a signed secp256k1 access key into the Tempo Accounts store.
52    ///
53    /// The signed authorization may be pending or already provisioned. The
54    /// access-key private key is persisted to `store.json`; the authorizing
55    /// root key is never stored.
56    ImportAccessKey {
57        /// Root Tempo account controlled by the access key.
58        #[arg(long)]
59        account: Address,
60
61        /// Access-key private key to persist.
62        #[arg(long, env = "TEMPO_ACCESS_KEY", hide_env_values = true)]
63        access_key: PrivateKeySigner,
64
65        /// Signed key authorization encoded as RLP hex.
66        #[arg(long)]
67        authorization: String,
68    },
69}
70
71impl TempoSubcommand {
72    pub async fn run(self) -> Result<()> {
73        match self {
74            Self::Zone(args) => args.run().await,
75            Self::Login { chain_id, no_browser } => {
76                let mut cfg = EnsureAccessKeyConfig::from_env(chain_id);
77                cfg.no_browser |= no_browser;
78                let outcome = ensure_access_key(cfg).await?;
79                let _ = foundry_common::sh_status!(
80                    "Authorized key {} for wallet {} on chain {}",
81                    outcome.key_address,
82                    outcome.wallet_address,
83                    outcome.chain_id,
84                );
85                Ok(())
86            }
87            Self::ImportAccessKey { account, access_key, authorization } => {
88                let authorization =
89                    decode_key_authorization::<SignedKeyAuthorization>(&authorization)?;
90                let chain_id = authorization.chain_id;
91                let key_address = access_key.address();
92                let store = TempoAccountsStore::default_path()?;
93                store.upsert_secp256k1_access_key(account, &access_key, &authorization)?;
94                let _ = foundry_common::sh_status!(
95                    "Imported access key {} for wallet {} on chain {} into {}",
96                    key_address,
97                    account,
98                    chain_id,
99                    store.path().display(),
100                );
101                Ok(())
102            }
103        }
104    }
105}