forge_script/
multi_sequence.rs1use eyre::{ContextCompat, Result, WrapErr};
2use forge_script_sequence::{
3 DRY_RUN_DIR, ScriptSequence, SensitiveScriptSequence, now, sig_to_file_name,
4};
5use foundry_common::{fs, shell};
6use foundry_compilers::ArtifactId;
7use foundry_config::Config;
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11#[derive(Clone, Default, Serialize, Deserialize)]
13pub struct MultiChainSequence {
14 pub deployments: Vec<ScriptSequence>,
15 #[serde(skip)]
16 pub path: PathBuf,
17 #[serde(skip)]
18 pub sensitive_path: PathBuf,
19 pub timestamp: u128,
20}
21
22#[derive(Clone, Default, Serialize, Deserialize)]
24pub struct SensitiveMultiChainSequence {
25 pub deployments: Vec<SensitiveScriptSequence>,
26}
27
28impl SensitiveMultiChainSequence {
29 fn from_multi_sequence(sequence: &MultiChainSequence) -> Self {
30 Self {
31 deployments: sequence.deployments.iter().map(SensitiveScriptSequence::from).collect(),
32 }
33 }
34}
35
36impl MultiChainSequence {
37 pub fn new(
38 deployments: Vec<ScriptSequence>,
39 sig: &str,
40 target: &ArtifactId,
41 config: &Config,
42 dry_run: bool,
43 ) -> Result<Self> {
44 let (path, sensitive_path) = Self::get_paths(config, sig, target, dry_run)?;
45
46 Ok(Self { deployments, path, sensitive_path, timestamp: now().as_millis() })
47 }
48
49 pub fn get_paths(
53 config: &Config,
54 sig: &str,
55 target: &ArtifactId,
56 dry_run: bool,
57 ) -> Result<(PathBuf, PathBuf)> {
58 let mut broadcast = config.broadcast.to_path_buf();
59 let mut cache = config.cache_path.to_path_buf();
60 let mut common = PathBuf::new();
61
62 common.push("multi");
63
64 if dry_run {
65 common.push(DRY_RUN_DIR);
66 }
67
68 let target_fname = target
69 .source
70 .file_name()
71 .wrap_err_with(|| format!("No filename for {:?}", target.source))?
72 .to_string_lossy();
73
74 common.push(format!("{target_fname}-latest"));
75
76 broadcast.push(common.clone());
77 cache.push(common);
78
79 fs::create_dir_all(&broadcast)?;
80 fs::create_dir_all(&cache)?;
81
82 let filename = format!("{}.json", sig_to_file_name(sig));
83
84 broadcast.push(filename.clone());
85 cache.push(filename);
86
87 Ok((broadcast, cache))
88 }
89
90 pub fn load(config: &Config, sig: &str, target: &ArtifactId, dry_run: bool) -> Result<Self> {
92 let (path, sensitive_path) = Self::get_paths(config, sig, target, dry_run)?;
93 let mut sequence: Self = foundry_compilers::utils::read_json_file(&path)
94 .wrap_err("Multi-chain deployment not found.")?;
95 let sensitive_sequence: SensitiveMultiChainSequence =
96 foundry_compilers::utils::read_json_file(&sensitive_path)
97 .wrap_err("Multi-chain deployment sensitive details not found.")?;
98
99 sequence.deployments.iter_mut().enumerate().for_each(|(i, sequence)| {
100 sequence.fill_sensitive(&sensitive_sequence.deployments[i]);
101 });
102
103 sequence.path = path;
104 sequence.sensitive_path = sensitive_path;
105
106 Ok(sequence)
107 }
108
109 pub fn save(&mut self, silent: bool, save_ts: bool) -> Result<()> {
111 self.deployments.iter_mut().for_each(|sequence| sequence.sort_receipts());
112
113 self.timestamp = now().as_millis();
114
115 let sensitive_sequence = SensitiveMultiChainSequence::from_multi_sequence(&*self);
116
117 fs::write_pretty_json_file(&self.path, self)?;
120
121 if save_ts {
122 let path = self.path.to_string_lossy();
124 let file = PathBuf::from(&path.replace("-latest", &format!("-{}", self.timestamp)));
125 fs::create_dir_all(file.parent().unwrap())?;
126 fs::copy(&self.path, &file)?;
127 }
128
129 fs::write_pretty_json_file(&self.sensitive_path, &sensitive_sequence)?;
132
133 if save_ts {
134 let path = self.sensitive_path.to_string_lossy();
136 let file = PathBuf::from(&path.replace("-latest", &format!("-{}", self.timestamp)));
137 fs::create_dir_all(file.parent().unwrap())?;
138 fs::copy(&self.sensitive_path, &file)?;
139 }
140
141 if !silent {
142 if shell::is_json() {
143 sh_println!(
144 "{}",
145 serde_json::json!({
146 "status": "success",
147 "transactions": self.path.display().to_string(),
148 "sensitive": self.sensitive_path.display().to_string(),
149 })
150 )?;
151 } else {
152 sh_println!("\nTransactions saved to: {}\n", self.path.display())?;
153 sh_println!("Sensitive details saved to: {}\n", self.sensitive_path.display())?;
154 }
155 }
156
157 Ok(())
158 }
159}