Skip to content

Commit 3968e6e

Browse files
committed
gnd: Fetch contract info before prompts in interactive init mode
The init command's interactive mode now fetches contract information (ABI, name, start block) from Etherscan/Sourcify immediately after the user provides the network and contract address, before prompting for remaining values. This allows fetched values to be used as defaults: - Contract name defaults to the fetched name - Start block defaults to the fetched deployment block - ABI prompt is skipped if fetch was successful Addresses PR #6282 review feedback issue I1.
1 parent 14c26a3 commit 3968e6e

File tree

3 files changed

+85
-11
lines changed

3 files changed

+85
-11
lines changed

gnd/src/commands/init.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ async fn run_interactive(opt: InitOpt) -> Result<()> {
204204
start_block,
205205
opt.index_events,
206206
opt.abi.clone().map(|p| p.to_string_lossy().to_string()),
207-
)?;
207+
)
208+
.await?;
208209

209210
// Execute based on source type
210211
match form.source_type {

gnd/src/output/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub enum Step {
1919
Deploy,
2020
/// Done with all steps
2121
Done,
22+
/// Warning (non-fatal)
23+
Warn,
2224
}
2325

2426
/// Print a standalone step without a spinner.
@@ -33,6 +35,7 @@ pub fn step(step_type: Step, message: &str) {
3335
Step::Skip => style("→").dim(),
3436
Step::Deploy => style("→").cyan(),
3537
Step::Done => style("✔").green(),
38+
Step::Warn => style("⚠").yellow(),
3639
};
3740
println!("{} {}", symbol, message);
3841
}

gnd/src/prompt.rs

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use console::{style, Term};
88
use inquire::validator::Validation;
99
use inquire::{Autocomplete, Confirm, CustomUserError, Select, Text};
1010

11-
use crate::services::{Network, NetworksRegistry};
11+
use crate::output::{step, Step};
12+
use crate::services::{ContractInfo, ContractService, Network, NetworksRegistry};
1213

1314
/// Format a network for display.
1415
fn format_network(network: &Network) -> String {
@@ -347,8 +348,14 @@ pub struct InitForm {
347348

348349
impl InitForm {
349350
/// Run the interactive form, filling in missing values.
351+
///
352+
/// The flow for contract mode is:
353+
/// 1. Prompt for network (if not provided)
354+
/// 2. Prompt for contract address (if not provided)
355+
/// 3. Fetch contract info from Etherscan/Sourcify (ABI, name, start block)
356+
/// 4. Use fetched values as defaults for remaining prompts
350357
#[allow(clippy::too_many_arguments)]
351-
pub fn run_interactive(
358+
pub async fn run_interactive(
352359
registry: &NetworksRegistry,
353360
// Pre-filled values from CLI args
354361
network: Option<String>,
@@ -398,22 +405,34 @@ impl InitForm {
398405

399406
// For contract mode, we need network, address, etc.
400407

401-
// Network
408+
// Step 1: Network
402409
let network = match network {
403410
Some(n) => n,
404411
None => prompt_network_interactive(registry)?,
405412
};
406413

407-
// Contract address
414+
// Step 2: Contract address
408415
let contract_address = match from_contract {
409416
Some(addr) => addr,
410417
None => prompt_contract_address()?,
411418
};
412419

413-
// Contract name
420+
// Step 3: Fetch contract info immediately after getting address
421+
// This allows us to use fetched values as defaults for remaining prompts
422+
let fetched_info = if abi_path.is_none() {
423+
fetch_contract_info_interactive(&network, &contract_address).await
424+
} else {
425+
None
426+
};
427+
428+
// Step 4: Contract name (use fetched name as default)
429+
let default_contract_name = fetched_info
430+
.as_ref()
431+
.map(|info| info.name.clone())
432+
.or_else(|| contract_name.clone());
414433
let contract_name = match contract_name {
415434
Some(n) => n,
416-
None => prompt_contract_name(None)?,
435+
None => prompt_contract_name(default_contract_name.as_deref())?,
417436
};
418437

419438
// Subgraph name
@@ -430,17 +449,28 @@ impl InitForm {
430449
None => prompt_directory(Some(&default_dir))?,
431450
};
432451

433-
// ABI path (optional)
452+
// ABI path - only prompt if we didn't fetch it successfully
434453
let abi_path = match abi_path {
435454
Some(p) => Some(p),
436-
None => prompt_abi_path()?,
455+
None => {
456+
if fetched_info.is_some() {
457+
// We successfully fetched the ABI, no need to prompt
458+
None
459+
} else {
460+
prompt_abi_path()?
461+
}
462+
}
437463
};
438464

439-
// Start block
465+
// Start block (use fetched start block as default)
466+
let default_start_block = fetched_info
467+
.as_ref()
468+
.and_then(|info| info.start_block)
469+
.or(start_block);
440470
let start_block = if start_block.is_some() {
441471
start_block
442472
} else {
443-
prompt_start_block(None)?
473+
prompt_start_block(default_start_block)?
444474
};
445475

446476
// Index events
@@ -464,6 +494,46 @@ impl InitForm {
464494
}
465495
}
466496

497+
/// Fetch contract info from Etherscan/Sourcify with status feedback.
498+
///
499+
/// Returns None if fetching fails (the prompts will fall back to manual entry).
500+
async fn fetch_contract_info_interactive(network: &str, address: &str) -> Option<ContractInfo> {
501+
step(
502+
Step::Load,
503+
&format!("Fetching contract info for {} on {}", address, network),
504+
);
505+
506+
// Load the contract service
507+
let service = match ContractService::load().await {
508+
Ok(s) => s,
509+
Err(e) => {
510+
step(
511+
Step::Warn,
512+
&format!("Could not load contract service: {}", e),
513+
);
514+
return None;
515+
}
516+
};
517+
518+
// Fetch the contract info
519+
match service.get_contract_info(network, address).await {
520+
Ok(info) => {
521+
step(Step::Done, &format!("Found contract: {}", info.name));
522+
Some(info)
523+
}
524+
Err(e) => {
525+
step(
526+
Step::Warn,
527+
&format!(
528+
"Could not fetch contract info: {}. You'll need to provide an ABI file.",
529+
e
530+
),
531+
);
532+
None
533+
}
534+
}
535+
}
536+
467537
/// Prompt for network selection using the simple completer.
468538
fn prompt_network_interactive(registry: &NetworksRegistry) -> Result<String> {
469539
let completer = SimpleNetworkCompleter::new(registry);

0 commit comments

Comments
 (0)