1use crate::{
2 cmd::tip20::send_tip20_transaction,
3 tempo::{ensure_tempo_precompile_active, print_payload, tempo_provider},
4 tx::{SendTxOpts, TxParams},
5};
6use alloy_ens::NameOrAddress;
7use alloy_primitives::Address;
8use alloy_sol_types::SolCall;
9use clap::{Parser, ValueEnum};
10use eyre::Result;
11use foundry_cli::opts::RpcOpts;
12use foundry_common::provider::RetryProvider;
13use foundry_evm::hardfork::TempoHardfork;
14use serde_json::{Value, json};
15use std::str::FromStr;
16use tempo_alloy::TempoNetwork;
17use tempo_contracts::precompiles::{IStorageCredits, STORAGE_CREDITS_ADDRESS};
18
19#[derive(Debug, Parser, Clone)]
25pub enum StorageCreditsSubcommand {
26 Balance {
28 #[arg(value_parser = NameOrAddress::from_str)]
30 account: NameOrAddress,
31
32 #[command(flatten)]
33 rpc: RpcOpts,
34 },
35
36 Mode {
41 #[arg(value_parser = NameOrAddress::from_str)]
43 account: NameOrAddress,
44
45 #[command(flatten)]
46 rpc: RpcOpts,
47 },
48
49 Budget {
54 #[arg(value_parser = NameOrAddress::from_str)]
56 account: NameOrAddress,
57
58 #[command(flatten)]
59 rpc: RpcOpts,
60 },
61
62 SetMode {
67 #[arg(value_enum)]
69 mode: CreditMode,
70
71 #[command(flatten)]
72 send_tx: SendTxOpts,
73
74 #[command(flatten)]
75 tx: TxParams,
76 },
77
78 SetBudget {
83 credits: u64,
85
86 #[command(flatten)]
87 send_tx: SendTxOpts,
88
89 #[command(flatten)]
90 tx: TxParams,
91 },
92}
93
94#[derive(Debug, Clone, Copy, ValueEnum)]
96pub enum CreditMode {
97 Refund,
99 Preserve,
101 Direct,
103}
104
105impl StorageCreditsSubcommand {
106 pub async fn run(self) -> Result<()> {
107 match self {
108 Self::Balance { account, rpc } => {
109 read(account, rpc, "balance", "Balance:", |credits, account| async move {
110 Ok(json!(credits.balanceOf(account).call().await?))
111 })
112 .await
113 }
114 Self::Mode { account, rpc } => {
115 read(account, rpc, "mode", "Mode: ", |credits, account| async move {
116 Ok(json!(credits.modeOf(account).call().await?.as_str()))
117 })
118 .await
119 }
120 Self::Budget { account, rpc } => {
121 read(account, rpc, "budget", "Budget: ", |credits, account| async move {
122 Ok(json!(credits.budgetOf(account).call().await?))
123 })
124 .await
125 }
126 Self::SetMode { mode, send_tx, tx } => {
127 ensure_t7(&send_tx.eth.rpc, "cast storage-credits set-mode").await?;
128 let new_mode = match mode {
129 CreditMode::Refund => IStorageCredits::Mode::Refund,
130 CreditMode::Preserve => IStorageCredits::Mode::Preserve,
131 CreditMode::Direct => IStorageCredits::Mode::Direct,
132 };
133 let data = IStorageCredits::setModeCall { newMode: new_mode }.abi_encode();
134 send_tip20_transaction(STORAGE_CREDITS_ADDRESS, data, send_tx, tx).await
135 }
136 Self::SetBudget { credits, send_tx, tx } => {
137 ensure_t7(&send_tx.eth.rpc, "cast storage-credits set-budget").await?;
138 let data = IStorageCredits::setBudgetCall { credits }.abi_encode();
139 send_tip20_transaction(STORAGE_CREDITS_ADDRESS, data, send_tx, tx).await
140 }
141 }
142 }
143}
144
145type Credits = IStorageCredits::IStorageCreditsInstance<RetryProvider<TempoNetwork>, TempoNetwork>;
146
147async fn read<F, Fut>(
150 account: NameOrAddress,
151 rpc: RpcOpts,
152 key: &str,
153 label: &str,
154 query: F,
155) -> Result<()>
156where
157 F: FnOnce(Credits, Address) -> Fut,
158 Fut: Future<Output = Result<Value>>,
159{
160 let provider = ensure_t7(&rpc, &format!("cast storage-credits {key}")).await?;
161 let account = account.resolve(&provider).await?;
162 let value = query(IStorageCredits::new(STORAGE_CREDITS_ADDRESS, provider), account).await?;
163 let payload = json!({ "account": format!("{account}"), key: value });
164 print_payload(payload, |payload| {
165 let value = &payload[key];
166 let value = value.as_str().map_or_else(|| value.to_string(), str::to_string);
167 sh_println!("Account: {}\n{label} {value}", payload["account"].as_str().unwrap_or_default())
168 })
169}
170
171async fn ensure_t7(rpc: &RpcOpts, command: &str) -> Result<RetryProvider<TempoNetwork>> {
175 let (_, provider) = tempo_provider(rpc)?;
176 ensure_tempo_precompile_active(
177 &provider,
178 TempoHardfork::T7,
179 STORAGE_CREDITS_ADDRESS,
180 &format!("{command} requires a Tempo T7-capable StorageCredits RPC"),
181 )
182 .await?;
183 Ok(provider)
184}