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}