Skip to main content

cast/cmd/vaddr/
create.rs

1use crate::{
2    cmd::tip20::mine::{self, RegisterMessages},
3    tx::{SendTxOpts, TxParams},
4};
5use alloy_primitives::{Address, B256};
6use eyre::Result;
7use foundry_cli::json::print_json_success;
8use foundry_common::shell;
9use serde_json::json;
10use tempo_primitives::{TempoAddressExt, UserTag};
11
12const MESSAGES: RegisterMessages = RegisterMessages {
13    no_signer: "cast vaddr create requires a signer (for example --private-key or --from)",
14    mismatch: "signer mismatch: salt is for",
15    submitting: "...",
16};
17
18/// Largest 6-byte user tag.
19const MAX_USER_TAG: u64 = 0x0000_FFFF_FFFF_FFFF;
20
21#[allow(clippy::too_many_arguments)]
22pub(super) async fn run(
23    owner: Address,
24    salt: Option<B256>,
25    tag: u64,
26    count: u32,
27    threads: Option<usize>,
28    seed: Option<B256>,
29    no_random: bool,
30    no_register: bool,
31    send_tx: SendTxOpts,
32    tx_opts: TxParams,
33) -> Result<()> {
34    if count == 0 {
35        return Ok(());
36    }
37
38    let json = shell::is_json();
39    let (output, elapsed) = mine::find_salt(owner, salt, threads, seed, no_random, json, "owner")?;
40    if let Some(elapsed) = elapsed
41        && !json
42    {
43        sh_status!("Found salt in {elapsed:?}")?;
44    }
45
46    let mut virtual_addresses = Vec::with_capacity(count as usize);
47    for i in 0..count {
48        let tag_value = tag
49            .checked_add(i as u64)
50            .filter(|&t| t <= MAX_USER_TAG)
51            .ok_or_else(|| eyre::eyre!("tag overflow: tag + count exceeds the 6-byte user tag range (max {MAX_USER_TAG:#x})"))?;
52        let user_tag = UserTag::new(tag_value.to_be_bytes()[2..].try_into().unwrap());
53        virtual_addresses.push((user_tag, Address::new_virtual(output.master_id, user_tag)));
54    }
55
56    let mut payload = json!({
57        "salt": format!("{}", output.salt),
58        "registration_hash": format!("{}", output.registration_hash),
59        "master_id": format!("{}", output.master_id),
60        "virtual_addresses": virtual_addresses.iter().map(|(tag, addr)| json!({
61            "tag": format!("{tag}"),
62            "address": format!("{addr}"),
63        })).collect::<Vec<_>>(),
64    });
65
66    if !json {
67        sh_println!(
68            "Salt:              {}\nRegistration hash: {}\nMaster ID:         {}",
69            output.salt,
70            output.registration_hash,
71            output.master_id,
72        )?;
73        sh_println!("\nVirtual addresses:")?;
74        for (tag, vaddr) in &virtual_addresses {
75            sh_println!("  tag={tag}  {vaddr}")?;
76        }
77    }
78
79    if !no_register {
80        let tx_hash =
81            mine::register_virtual_master(owner, output.salt, send_tx, tx_opts, json, &MESSAGES)
82                .await?;
83        payload["registration_tx_hash"] = json!(format!("{tx_hash:#x}"));
84    }
85    if json {
86        print_json_success(payload)?;
87    }
88    Ok(())
89}