diff --git a/rs/rosetta-api/icrc1/rosetta/BUILD.bazel b/rs/rosetta-api/icrc1/rosetta/BUILD.bazel index 0ddea8ae56a..3323756adb8 100644 --- a/rs/rosetta-api/icrc1/rosetta/BUILD.bazel +++ b/rs/rosetta-api/icrc1/rosetta/BUILD.bazel @@ -23,6 +23,8 @@ DEPENDENCIES = [ "@crate_index//:hex", "@crate_index//:serde_cbor", "@crate_index//:rand_0_8_4", + "@crate_index//:lazy_static", + "@crate_index//:url", "//packages/icrc-ledger-types:icrc_ledger_types", "//packages/icrc-ledger-agent:icrc_ledger_agent", "//rs/rosetta-api/icrc1/ledger", @@ -45,8 +47,6 @@ DEV_DEPENDENCIES = [ "@crate_index//:ring", "@crate_index//:once_cell", "@crate_index//:reqwest", - "@crate_index//:url", - "@crate_index//:lazy_static", ] MACRO_DEPENDENCIES = [ diff --git a/rs/rosetta-api/icrc1/rosetta/Cargo.toml b/rs/rosetta-api/icrc1/rosetta/Cargo.toml index 396f375ccc8..e8a40d32232 100644 --- a/rs/rosetta-api/icrc1/rosetta/Cargo.toml +++ b/rs/rosetta-api/icrc1/rosetta/Cargo.toml @@ -33,17 +33,17 @@ ic-icrc1 = { path = ".." } proptest = "1.0" rand = "0.8.4" axum = "0.6.1" +url = "2.2.1" clap = { version = "4.0.29", features = ["derive"] } tokio = { version = "1.15.0", features = ["full"] } ic-agent = "=0.22.0" icrc-ledger-agent = { path = "../../../../packages/icrc-ledger-agent" } hex = "0.4.2" ic-crypto-tree-hash = { path = "../../../crypto/tree_hash" } - +lazy_static = "1.4.0" [lib] path = "src/lib.rs" -proptest = "1.0" [dev-dependencies] ic-icrc1-ledger-sm-tests = { path = "../ledger/sm-tests" } diff --git a/rs/rosetta-api/icrc1/rosetta/src/main.rs b/rs/rosetta-api/icrc1/rosetta/src/main.rs index 53873d41bcf..3c15deddcb8 100644 --- a/rs/rosetta-api/icrc1/rosetta/src/main.rs +++ b/rs/rosetta-api/icrc1/rosetta/src/main.rs @@ -5,19 +5,36 @@ use axum::{ }; use clap::{Parser, ValueEnum}; use endpoints::{health, network_list, network_options}; +use ic_agent::{ + agent::http_transport::ReqwestHttpReplicaV2Transport, identity::AnonymousIdentity, Agent, +}; use ic_base_types::CanisterId; use ic_icrc_rosetta::{common::storage::storage_client::StorageClient, AppState}; +use icrc_ledger_agent::Icrc1Agent; +use lazy_static::lazy_static; +use log::debug; use std::path::PathBuf; use std::{net::TcpListener, sync::Arc}; - +use url::Url; mod endpoints; +lazy_static! { + static ref MAINNET_DEFAULT_URL: &'static str = "https://ic0.app"; + static ref TESTNET_DEFAULT_URL: &'static str = "https://exchanges.testnet.dfinity.network"; +} + #[derive(Clone, Debug, ValueEnum)] enum StoreType { InMemory, File, } +#[derive(Clone, Debug, ValueEnum)] +enum NetworkType { + Mainnet, + Testnet, +} + #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { @@ -41,6 +58,16 @@ struct Args { /// The file to use for the store if [store_type] is file. #[arg(short = 'f', long, default_value = "db.sqlite")] store_file: PathBuf, + + /// The network type that rosetta connects to. + #[arg(short = 'n', long, value_enum)] + network_type: NetworkType, + + /// URL of the IC to connect to. + /// Default Mainnet URL is: https://ic0.app, + /// Default Testnet URL is: https://exchanges.testnet.dfinity.network + #[arg(long, short = 'u')] + network_url: Option, } impl Args { @@ -52,6 +79,22 @@ impl Args { (Some(port), _) => *port, } } + fn is_mainnet(&self) -> bool { + match self.network_type { + NetworkType::Mainnet => true, + NetworkType::Testnet => false, + } + } + + fn effective_network_url(&self) -> String { + self.network_url.clone().unwrap_or_else(|| { + if self.is_mainnet() { + (*MAINNET_DEFAULT_URL).to_string() + } else { + (*TESTNET_DEFAULT_URL).to_string() + } + }) + } } #[tokio::main] @@ -68,6 +111,34 @@ async fn main() -> Result<()> { _storage: storage, }); + let network_url = args.effective_network_url(); + + let ic_agent = Agent::builder() + .with_identity(AnonymousIdentity) + .with_transport(ReqwestHttpReplicaV2Transport::create( + Url::parse(&network_url) + .context(format!("Failed to parse URL {}", network_url.clone()))?, + )?) + .build()?; + + // Only fetch root key if the network is not the mainnet + if !args.is_mainnet() { + debug!("Network type is not mainnet --> Trying to fetch root key"); + ic_agent.fetch_root_key().await?; + } + + debug!("Rosetta connects to : {}", network_url); + + debug!( + "Network status is : {:?}", + ic_agent.status().await?.replica_health_status + ); + + let _icrc1_agent = Icrc1Agent { + agent: ic_agent, + ledger_canister_id: args.ledger_id.into(), + }; + let app = Router::new() .route("/health", get(health)) .route("/network/list", post(network_list))