foundry_common/tempo/
keystore.rs1use alloy_primitives::{Address, hex};
7use alloy_rlp::Decodable;
8use serde::Deserialize;
9use std::path::PathBuf;
10
11pub const TEMPO_PRIVATE_KEY_ENV: &str = "TEMPO_PRIVATE_KEY";
13
14pub const TEMPO_HOME_ENV: &str = "TEMPO_HOME";
16
17pub const DEFAULT_TEMPO_HOME: &str = ".tempo";
19
20pub const WALLET_KEYS_PATH: &str = "wallet/keys.toml";
22
23#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
25#[serde(rename_all = "lowercase")]
26pub enum WalletType {
27 #[default]
28 Local,
29 Passkey,
30}
31
32#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
34#[serde(rename_all = "lowercase")]
35pub enum KeyType {
36 #[default]
37 Secp256k1,
38 P256,
39 WebAuthn,
40}
41
42#[derive(Debug, Default, Deserialize)]
44pub struct StoredTokenLimit {
45 pub currency: Address,
46 pub limit: String,
47}
48
49#[derive(Debug, Default, Deserialize)]
54pub struct KeyEntry {
55 #[serde(default)]
57 pub wallet_type: WalletType,
58 #[serde(default)]
60 pub wallet_address: Address,
61 #[serde(default)]
63 pub chain_id: u64,
64 #[serde(default)]
66 pub key_type: KeyType,
67 #[serde(default)]
69 pub key_address: Option<Address>,
70 #[serde(default)]
72 pub key: Option<String>,
73 #[serde(default)]
76 pub key_authorization: Option<String>,
77 #[serde(default)]
79 pub expiry: Option<u64>,
80 #[serde(default)]
82 pub limits: Vec<StoredTokenLimit>,
83}
84
85impl KeyEntry {
86 pub fn has_inline_key(&self) -> bool {
88 self.key.as_ref().is_some_and(|k| !k.trim().is_empty())
89 }
90}
91
92#[derive(Debug, Default, Deserialize)]
94pub struct KeysFile {
95 #[serde(default)]
96 pub keys: Vec<KeyEntry>,
97}
98
99pub fn tempo_home() -> Option<PathBuf> {
103 if let Ok(home) = std::env::var(TEMPO_HOME_ENV) {
104 return Some(PathBuf::from(home));
105 }
106 dirs::home_dir().map(|h| h.join(DEFAULT_TEMPO_HOME))
107}
108
109pub fn tempo_keys_path() -> Option<PathBuf> {
111 tempo_home().map(|home| home.join(WALLET_KEYS_PATH))
112}
113
114pub fn read_tempo_keys_file() -> Option<KeysFile> {
119 let keys_path = tempo_keys_path()?;
120 if !keys_path.exists() {
121 tracing::trace!(?keys_path, "tempo keys file not found");
122 return None;
123 }
124
125 let contents = match std::fs::read_to_string(&keys_path) {
126 Ok(c) => c,
127 Err(e) => {
128 tracing::warn!(?keys_path, %e, "failed to read tempo keys file");
129 return None;
130 }
131 };
132
133 match toml::from_str(&contents) {
134 Ok(f) => Some(f),
135 Err(e) => {
136 tracing::warn!(?keys_path, %e, "failed to parse tempo keys file");
137 None
138 }
139 }
140}
141
142pub fn decode_key_authorization<T: Decodable>(hex_str: &str) -> eyre::Result<T> {
147 let bytes = hex::decode(hex_str)?;
148 let auth = T::decode(&mut bytes.as_slice())?;
149 Ok(auth)
150}