diff --git a/Cargo.lock b/Cargo.lock index 362a3887..e9e65ad2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4681,6 +4681,7 @@ name = "rosetta-config-ethereum" version = "0.4.0" dependencies = [ "anyhow", + "rosetta-config-astar", "rosetta-core", "serde", ] diff --git a/chains/astar/config/Cargo.toml b/chains/astar/config/Cargo.toml index 0a490066..0dd43af8 100644 --- a/chains/astar/config/Cargo.toml +++ b/chains/astar/config/Cargo.toml @@ -4,9 +4,13 @@ version = "0.4.0" edition = "2021" license = "MIT" repository = "https://github.com/analog-labs/chain-connectors" -description = "Polkadot configuration." +description = "Astar configuration." + +[features] +default = ["astar-metadata"] +astar-metadata = ["subxt"] [dependencies] anyhow = "1.0.69" rosetta-core = { version = "0.4.0", path = "../../../rosetta-core" } -subxt = "0.30" +subxt = { version = "0.30", default-features = false, features = ["substrate-compat", "native"], optional = true } diff --git a/chains/astar/config/src/lib.rs b/chains/astar/config/src/lib.rs index 924f0f80..b2c711f0 100644 --- a/chains/astar/config/src/lib.rs +++ b/chains/astar/config/src/lib.rs @@ -6,39 +6,64 @@ use rosetta_core::{ use std::sync::Arc; // Generate an interface that we can use from the node's metadata. +#[cfg(feature = "astar-metadata")] pub mod metadata { #[subxt::subxt(runtime_metadata_path = "res/astar-dev.scale")] pub mod dev {} } pub fn config(network: &str) -> Result { + // All available networks are listed here: + // https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/command.rs#L88-L100 + // TODO: refactor, this is ugly i know, but necessary because the string must be &'static + let (network, symbol) = match network { + // ref: https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/local/chain_spec.rs#L61-L63 + "dev" => ("dev", "LOC"), + + // ref: https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/parachain/chain_spec/astar.rs#L55-L57 + "astar" => ("astar", "ASTR"), + "astar-dev" => ("astar-dev", "ASTR"), + + // ref: https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/parachain/chain_spec/shibuya.rs#L59-L61 + "shibuya" => ("shibuya", "SBY"), + "shibuya-dev" => ("shibuya-dev", "SBY"), + + // ref: https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/parachain/chain_spec/shiden.rs#L56-L58 + "shiden" => ("shiden", "SDN"), + "shiden-dev" => ("shiden-dev", "SDN"), + + _ => anyhow::bail!("unsupported network: {}", network), + }; + Ok(BlockchainConfig { blockchain: "astar", - network: "dev", + network, algorithm: Algorithm::EcdsaRecoverableSecp256k1, address_format: AddressFormat::Eip55, - coin: 1, + coin: if network == "astar" { 810 } else { 1 }, bip44: true, utxo: false, currency_unit: "planck", - currency_symbol: "ASTR", + currency_symbol: symbol, currency_decimals: 18, - node_uri: NodeUri::parse("ws://127.0.0.1:9944")?, + node_uri: NodeUri::parse("ws://127.0.0.1:9945")?, node_image: "staketechnologies/astar-collator:v5.15.0", node_command: Arc::new(|network, port| { - vec![ + let mut params = vec![ "astar-collator".into(), format!("--chain={network}"), "--rpc-cors=all".into(), "--rpc-external".into(), format!("--rpc-port={port}"), - "--alice".into(), - "--tmp".into(), "--enable-evm-rpc".into(), - ] + ]; + if network.ends_with("dev") { + params.extend_from_slice(&["--alice".into(), "--tmp".into()]); + } + params }), node_additional_ports: &[], connector_port: 8083, - testnet: network == "dev", + testnet: network != "astar", }) } diff --git a/chains/bitcoin/config/src/lib.rs b/chains/bitcoin/config/src/lib.rs index 6fd503dd..58c0dbc4 100644 --- a/chains/bitcoin/config/src/lib.rs +++ b/chains/bitcoin/config/src/lib.rs @@ -5,29 +5,36 @@ use rosetta_core::{BlockchainConfig, NodeUri}; use std::sync::Arc; pub fn config(network: &str) -> Result { - anyhow::ensure!(network == "regtest"); + let (network, symbol, bip44_id) = match network { + "regtest" => ("regtest", "tBTC", 1), + "mainnet" => ("mainnet", "BTC", 0), + _ => anyhow::bail!("unsupported network: {}", network), + }; Ok(BlockchainConfig { blockchain: "bitcoin", - network: "regtest", + network, algorithm: Algorithm::EcdsaSecp256k1, address_format: AddressFormat::Bech32("bcrt"), - coin: 1, + coin: bip44_id, bip44: true, utxo: true, currency_unit: "satoshi", - currency_symbol: "tBTC", + currency_symbol: symbol, currency_decimals: 8, node_uri: NodeUri::parse("http://127.0.0.1:18443")?, node_image: "ruimarinho/bitcoin-core:23", - node_command: Arc::new(|_network, port| { - vec![ - "-regtest=1".into(), + node_command: Arc::new(|network, port| { + let mut params: Vec = vec![ "-rpcbind=0.0.0.0".into(), format!("-rpcport={port}"), "-rpcallowip=0.0.0.0/0".into(), "-rpcuser=rosetta".into(), "-rpcpassword=rosetta".into(), - ] + ]; + if network == "regtest" { + params.push("-regtest=1".into()); + } + params }), node_additional_ports: &[], connector_port: 8080, diff --git a/chains/ethereum/config/Cargo.toml b/chains/ethereum/config/Cargo.toml index fa0c70a2..6352cdd8 100644 --- a/chains/ethereum/config/Cargo.toml +++ b/chains/ethereum/config/Cargo.toml @@ -8,5 +8,6 @@ description = "Ethereum configuration." [dependencies] anyhow = "1.0.69" +rosetta-config-astar = { version = "0.4.0", default-features = false, path = "../../astar/config" } rosetta-core = { version = "0.4.0", path = "../../../rosetta-core" } serde = { version = "1.0.153", features = ["derive"] } diff --git a/chains/ethereum/config/src/lib.rs b/chains/ethereum/config/src/lib.rs index 850a60f1..69b98689 100644 --- a/chains/ethereum/config/src/lib.rs +++ b/chains/ethereum/config/src/lib.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use rosetta_config_astar::config as astar_config; use rosetta_core::crypto::address::AddressFormat; use rosetta_core::crypto::Algorithm; use rosetta_core::{BlockchainConfig, NodeUri}; @@ -6,7 +7,6 @@ use serde::{Deserialize, Serialize}; use std::sync::Arc; pub fn config(network: &str) -> Result { - anyhow::ensure!(network == "dev"); let config = match network { "dev" | "mainnet" => BlockchainConfig { blockchain: "ethereum", @@ -44,39 +44,9 @@ pub fn config(network: &str) -> Result { connector_port: 8081, testnet: network == "dev", }, - "astar" => BlockchainConfig { - blockchain: "astar", - // Astar networks are listed here: - // https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/command.rs#L56-L69 - network: "astar", - algorithm: Algorithm::EcdsaRecoverableSecp256k1, - address_format: AddressFormat::Eip55, - coin: 810, - bip44: true, - utxo: false, - currency_unit: "planck", - currency_symbol: "ASTR", - currency_decimals: 18, - // The default RPC port is 9945 - // https://github.com/AstarNetwork/Astar/blob/v5.15.0/bin/collator/src/command.rs#L965-L967 - node_uri: NodeUri::parse("http://127.0.0.1:9945")?, - node_image: "staketechnologies/astar-collator:v5.15.0", - node_command: Arc::new(|_network, port| { - vec![ - "astar-collator".into(), - format!("--chain=astar"), - "--rpc-cors=all".into(), - "--rpc-external".into(), - format!("--rpc-port={port}"), - "--alice".into(), - "--enable-evm-rpc".into(), - ] - }), - node_additional_ports: &[], - connector_port: 8083, - testnet: false, - }, - _ => anyhow::bail!("unsupported network: {}", network), + // Try to load the network config from astar + "astar-local" => astar_config("dev")?, + network => astar_config(network)?, }; Ok(config) } diff --git a/chains/polkadot/config/src/lib.rs b/chains/polkadot/config/src/lib.rs index 9c6ef800..99525835 100644 --- a/chains/polkadot/config/src/lib.rs +++ b/chains/polkadot/config/src/lib.rs @@ -4,6 +4,7 @@ use rosetta_core::crypto::Algorithm; use rosetta_core::{BlockchainConfig, NodeUri}; use serde::{Deserialize, Serialize}; use std::sync::Arc; +use subxt::ext::sp_core::crypto::Ss58AddressFormat; // Generate an interface that we can use from the node's metadata. pub mod metadata { @@ -11,49 +12,146 @@ pub mod metadata { pub mod dev {} } +#[derive(Debug, Clone, PartialEq)] +pub struct PolkadotNetworkProperties { + blockchain: &'static str, + network: &'static str, + symbol: &'static str, + bip44_id: u32, + decimals: u32, + ss58_format: Ss58AddressFormat, +} + +impl TryFrom<&str> for PolkadotNetworkProperties { + type Error = anyhow::Error; + + fn try_from(value: &str) -> std::result::Result { + // To see all available blockchains and networks, see: + // https://github.com/paritytech/polkadot/blob/v1.0.0/cli/src/command.rs#L93-L145 + // All blockchains in polkadot have "dev", "local" and "staging" variants + + // "dev" and "polkadot-dev" are the same + let chain = if value == "dev" { + "polkadot-dev" + } else { + value + }; + + // Split blockchain and network + let (blockchain, network) = chain.split_once('-').unwrap_or((chain, "")); + + // Convert blockchain to &'static str + let blockchain = match blockchain { + "polkadot" => "polkadot", + "kusama" => "kusama", + "rococo" => "rococo", + "westend" => "westend", + "wococo" => "wococo", + "versi" => "versi", + _ => anyhow::bail!("unsupported blockchain: {}", blockchain), + }; + + // Convert network to &'static str + let network = match network { + "" => "mainnet", + "dev" => "dev", + "local" => "local", + "staging" => "staging", + _ => anyhow::bail!("unsupported network: {blockchain}-{network}"), + }; + + // Get blockchain parameters + let (symbol, bip44_id, decimals, ss58_format) = match (blockchain, network) { + // Polkadot mainnet and dev networks + ("polkadot", "mainnet") => ("DOT", 354, 10, Ss58AddressFormatRegistry::PolkadotAccount), + ("polkadot", _) => ("DOT", 1, 10, Ss58AddressFormatRegistry::PolkadotAccount), + + // Kusama mainnet and dev networks + ("kusama", "mainnet") => ("KSM", 434, 12, Ss58AddressFormatRegistry::KusamaAccount), + ("kusama", _) => ("KSM", 1, 12, Ss58AddressFormatRegistry::KusamaAccount), + + // Rococo + ("rococo", _) => ("ROC", 1, 12, Ss58AddressFormatRegistry::SubstrateAccount), + + // Westend + ("westend", _) => ("WND", 1, 12, Ss58AddressFormatRegistry::SubstrateAccount), + + // Wococo + ("wococo", _) => ("WOCO", 1, 12, Ss58AddressFormatRegistry::SubstrateAccount), + + // Versi + ("versi", _) => ("VRS", 1, 12, Ss58AddressFormatRegistry::SubstrateAccount), + + _ => anyhow::bail!("unsupported network: {network}"), + }; + + Ok(Self { + blockchain, + network, + symbol, + bip44_id, + decimals, + ss58_format: ss58_format.into(), + }) + } +} + +impl PolkadotNetworkProperties { + // TODO: What is considered testnet? only local chains, or public testnets as well? + pub fn is_testnet(&self) -> bool { + self.network != "mainnet" + } + + pub fn is_live(&self) -> bool { + matches!(self.network, "mainnet" | "staging") + } +} + pub fn config(network: &str) -> Result { - let (network, kusama) = match network { - "dev" => ("dev", false), - "kusama" => ("kusama", true), - "polkadot" => ("polkadot", false), - _ => anyhow::bail!("unsupported network"), - }; + let properties = PolkadotNetworkProperties::try_from(network)?; + + let blockchain = properties.blockchain; Ok(BlockchainConfig { - blockchain: "polkadot", - network, + blockchain: properties.blockchain, + network: properties.network, algorithm: Algorithm::Sr25519, - address_format: AddressFormat::Ss58( - if kusama { - Ss58AddressFormatRegistry::PolkadotAccount - } else { - Ss58AddressFormatRegistry::KusamaAccount - } - .into(), - ), - coin: 1, + address_format: AddressFormat::Ss58(properties.ss58_format), + coin: properties.bip44_id, bip44: false, utxo: false, currency_unit: "planck", - currency_symbol: if kusama { "KSM" } else { "DOT" }, - currency_decimals: if kusama { 12 } else { 10 }, + currency_symbol: properties.symbol, + currency_decimals: properties.decimals, node_uri: NodeUri::parse("ws://127.0.0.1:9944")?, node_image: "parity/polkadot:v1.0.0", - node_command: Arc::new(|network, port| { - let chain = if network == "dev" { - "--dev".to_string() - } else { - format!("--chain={network}") + node_command: Arc::new(move |network, port| { + let chain = match network { + "mainnet" => blockchain.to_string(), + _ => format!("{blockchain}-{network}"), }; - vec![ - chain, - "--rpc-external".into(), - format!("--rpc-port={port}"), - "--alice".into(), - ] + match network { + "dev" | "local" => vec![ + format!("--chain={chain}"), + format!("--rpc-port={port}"), + "--rpc-external".into(), + "--force-authoring".into(), + "--rpc-cors=all".into(), + "--alice".into(), + "--tmp".into(), + "--allow-private-ip".into(), + "--no-mdns".into(), + ], + _ => vec![ + format!("--chain={chain}"), + format!("--rpc-port={port}"), + "--rpc-external".into(), + "--rpc-cors=all".into(), + ], + } }), node_additional_ports: &[], connector_port: 8082, - testnet: network == "dev", + testnet: properties.is_testnet(), }) }