1use crate::{
2 cmd::send::SendTxArgs,
3 tempo,
4 tx::{SendTxOpts, TxParams},
5};
6use alloy_ens::NameOrAddress;
7use alloy_primitives::{Address, B256};
8use clap::Parser;
9use eyre::Result;
10use foundry_cli::utils::get_chain;
11use std::str::FromStr;
12use tempo_alloy::TempoNetwork;
13
14mod create;
15pub(crate) use create::iso4217_warning_message;
16pub(crate) mod logo;
17pub(crate) mod mine;
18
19const MINE_REGISTER_MESSAGES: mine::RegisterMessages = mine::RegisterMessages {
20 no_signer: "--register requires a signer or Tempo keychain identity (for example --private-key or --from)",
21 mismatch: "registration sender mismatch: mined salt is for",
22 submitting: " on Tempo...",
23};
24
25#[derive(Debug, Parser, Clone)]
27pub enum Tip20Subcommand {
28 #[command(visible_alias = "c")]
30 Create {
31 name: String,
33
34 symbol: String,
36
37 currency: String,
41
42 #[arg(value_parser = NameOrAddress::from_str)]
44 quote_token: NameOrAddress,
45
46 #[arg(value_parser = NameOrAddress::from_str)]
48 admin: NameOrAddress,
49
50 salt: B256,
52
53 #[arg(long, value_name = "URI")]
55 logo_uri: Option<String>,
56
57 #[arg(long)]
59 force: bool,
60
61 #[command(flatten)]
62 send_tx: SendTxOpts,
63
64 #[command(flatten)]
65 tx: TxParams,
66 },
67
68 LogoCheck {
70 #[arg(value_name = "URI")]
72 logo_uri: String,
73 },
74
75 LogoSet {
77 #[arg(value_parser = NameOrAddress::from_str)]
79 token: NameOrAddress,
80
81 #[arg(value_name = "URI")]
83 logo_uri: String,
84
85 #[command(flatten)]
86 send_tx: SendTxOpts,
87
88 #[command(flatten)]
89 tx: TxParams,
90 },
91
92 #[command(visible_alias = "m")]
94 Mine {
95 #[arg(value_name = "ADDRESS")]
97 master: Address,
98
99 #[arg(long, conflicts_with_all = ["seed", "no_random"], value_name = "HEX")]
101 salt: Option<B256>,
102
103 #[arg(global = true, long, short = 'j', visible_alias = "jobs")]
105 threads: Option<usize>,
106
107 #[arg(long, value_name = "HEX")]
109 seed: Option<B256>,
110
111 #[arg(long, conflicts_with = "seed")]
113 no_random: bool,
114
115 #[arg(long, conflicts_with_all = ["seed", "no_random"])]
117 register: bool,
118
119 #[command(flatten)]
120 send_tx: SendTxOpts,
121
122 #[command(flatten)]
123 tx: TxParams,
124 },
125}
126
127impl Tip20Subcommand {
128 pub async fn run(self) -> Result<()> {
129 match self {
130 Self::Create {
131 name,
132 symbol,
133 currency,
134 quote_token,
135 admin,
136 salt,
137 logo_uri,
138 force,
139 send_tx,
140 tx,
141 } => {
142 create::run(
143 name,
144 symbol,
145 currency,
146 quote_token,
147 admin,
148 salt,
149 logo_uri,
150 force,
151 send_tx,
152 tx,
153 )
154 .await
155 }
156 Self::LogoCheck { logo_uri } => logo::check(&logo_uri),
157 Self::LogoSet { token, logo_uri, send_tx, tx } => {
158 logo::set(token, logo_uri, send_tx, tx).await
159 }
160 Self::Mine { master, salt, threads, seed, no_random, register, send_tx, tx } => {
161 let output = mine::run(master, salt, threads, seed, no_random)?;
162 if register {
163 let msgs = &MINE_REGISTER_MESSAGES;
164 mine::register_virtual_master(master, output.salt, send_tx, tx, false, msgs)
165 .await?;
166 }
167 Ok(())
168 }
169 }
170 }
171}
172
173pub(crate) async fn send_tip20_transaction(
176 to: Address,
177 data: Vec<u8>,
178 send_tx: SendTxOpts,
179 tx: TxParams,
180) -> Result<()> {
181 tempo::ensure_session_not_browser(&tx.tempo, send_tx.browser.browser)?;
182 let (config, provider) = tempo::tempo_provider(&send_tx.eth.rpc)?;
183 let chain = get_chain(config.chain, &provider).await?;
184 let (signer, access_key) =
185 tempo::resolve_session_or_wallet_signer(&tx.tempo, &send_tx.eth.wallet, chain.id()).await?;
186 SendTxArgs::contract_call(NameOrAddress::Address(to), data, send_tx, tx)
187 .run_generic::<TempoNetwork>(signer, access_key)
188 .await
189}