Skip to main content

cast/cmd/vaddr/
mod.rs

1use crate::tx::{SendTxOpts, TxParams};
2use alloy_primitives::{Address, B256};
3use clap::Parser;
4use foundry_cli::opts::RpcOpts;
5
6mod create;
7mod resolve;
8mod watch;
9
10/// TIP-1022 virtual address registry operations (Tempo).
11///
12/// Virtual addresses are deterministic 20-byte aliases (masterId || VIRTUAL_MAGIC || userTag)
13/// that auto-forward TIP-20 deposits to a registered master wallet at the protocol level,
14/// with no on-chain sweep transaction required.
15///
16/// See: <https://docs.tempo.xyz/protocol/tips/tip-1022>
17#[derive(Debug, Parser, Clone)]
18pub enum VaddrSubcommand {
19    /// Mine a TIP-1022 proof-of-work salt, register as a virtual address master, and print
20    /// derived virtual addresses for the given owner.
21    #[command(visible_alias = "c")]
22    Create {
23        /// The master (owner) address that will control all virtual addresses under this
24        /// registration. Must not be the zero address, a virtual address, or a TIP-20 token.
25        #[arg(long, value_name = "ADDRESS")]
26        owner: Address,
27
28        /// Use this salt directly instead of mining one. Must satisfy the 32-bit PoW requirement.
29        #[arg(long, conflicts_with_all = ["seed", "no_random"], value_name = "HEX")]
30        salt: Option<B256>,
31
32        /// Starting user tag for the derived virtual address output (hex-encoded 6 bytes).
33        #[arg(long, default_value = "0", value_name = "U64")]
34        tag: u64,
35
36        /// Number of virtual addresses to derive and print.
37        #[arg(long, default_value = "1", value_name = "N")]
38        count: u32,
39
40        /// Number of threads to use for mining. Defaults to number of logical cores.
41        #[arg(long, short = 'j', visible_alias = "jobs")]
42        threads: Option<usize>,
43
44        /// Seed for the random number generator used to initialize the salt search.
45        #[arg(long, value_name = "HEX")]
46        seed: Option<B256>,
47
48        /// Start salt search from zero instead of a random value.
49        #[arg(long, conflicts_with = "seed")]
50        no_random: bool,
51
52        /// Mine and print the salt and derived virtual addresses without submitting the
53        /// registerVirtualMaster transaction.
54        #[arg(long)]
55        no_register: bool,
56
57        #[command(flatten)]
58        send_tx: Box<SendTxOpts>,
59
60        #[command(flatten)]
61        tx: Box<TxParams>,
62    },
63
64    /// Resolve a virtual address to its registered master and decode its components.
65    #[command(visible_alias = "r")]
66    Resolve {
67        /// The virtual address to resolve.
68        #[arg(value_name = "ADDRESS")]
69        addr: Address,
70
71        #[command(flatten)]
72        rpc: RpcOpts,
73    },
74
75    /// Watch (tail) incoming TIP-20 transfers to a virtual address.
76    #[command(visible_alias = "w")]
77    Watch {
78        /// The virtual address to monitor.
79        #[arg(value_name = "ADDRESS")]
80        addr: Address,
81
82        /// Filter on a specific TIP-20 token address. Watches all tokens if omitted.
83        #[arg(long, value_name = "ADDRESS")]
84        token: Option<Address>,
85
86        /// Block number to start from. Defaults to the current latest block.
87        #[arg(long, value_name = "BLOCK")]
88        from_block: Option<u64>,
89
90        #[command(flatten)]
91        rpc: RpcOpts,
92    },
93}
94
95impl VaddrSubcommand {
96    pub async fn run(self) -> eyre::Result<()> {
97        match self {
98            Self::Create {
99                owner,
100                salt,
101                tag,
102                count,
103                threads,
104                seed,
105                no_random,
106                no_register,
107                send_tx,
108                tx,
109            } => {
110                create::run(
111                    owner,
112                    salt,
113                    tag,
114                    count,
115                    threads,
116                    seed,
117                    no_random,
118                    no_register,
119                    *send_tx,
120                    *tx,
121                )
122                .await?
123            }
124            Self::Resolve { addr, rpc } => resolve::run(addr, rpc).await?,
125            Self::Watch { addr, token, from_block, rpc } => {
126                watch::run(addr, token, from_block, rpc).await?
127            }
128        }
129        Ok(())
130    }
131}