Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/primitives/src/block_explorer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub trait BlockExplorer: Send + Sync {
fn get_token_url(&self, _token: &str) -> Option<String> {
None
}
fn get_nft_url(&self, _contract: &str, _token_id: &str) -> Option<String> {
None
}
fn get_validator_url(&self, _validator: &str) -> Option<String> {
None
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/algorand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl AlgorandAllo {
tx_path: TX_PATH,
address_path: ACCOUNT_PATH,
token_path: None,
nft_path: None,
validator_path: Some(ACCOUNT_PATH),
})
}
Expand Down
2 changes: 2 additions & 0 deletions crates/primitives/src/explorers/aptos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn new_aptos_scan() -> Box<dyn BlockExplorer> {
tx_path: TRANSACTION_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(COIN_PATH),
nft_path: None,
validator_path: None,
})
}
Expand All @@ -19,6 +20,7 @@ pub fn new_aptos_explorer() -> Box<dyn BlockExplorer> {
tx_path: TXN_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(COIN_PATH),
nft_path: None,
validator_path: None,
})
}
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/blockvision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ impl BlockVision {
tx_path: "/txblock",
address_path: ACCOUNT_PATH,
token_path: Some(COIN_PATH),
nft_path: None,
validator_path: Some(VALIDATORS_PATH),
})
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/chainflip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl ChainflipScan {
tx_path: TX_PATH,
address_path: "",
token_path: None,
nft_path: None,
validator_path: None,
})
}
Expand Down
25 changes: 24 additions & 1 deletion crates/primitives/src/explorers/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub const TRANSACTION_PATH: &str = "/transaction";
pub const ADDRESS_PATH: &str = "/address";
pub const ACCOUNT_PATH: &str = "/account";
pub const TOKEN_PATH: &str = "/token";
pub const NFT_PATH: &str = "/nft";
pub const COIN_PATH: &str = "/coin";
pub const VALIDATOR_PATH: &str = "/validator";
pub const VALIDATORS_PATH: &str = "/validators";
Expand All @@ -21,6 +22,7 @@ pub struct Metadata {
pub tx_path: &'static str,
pub address_path: &'static str,
pub token_path: Option<&'static str>,
pub nft_path: Option<&'static str>,
pub validator_path: Option<&'static str>,
}

Expand All @@ -33,18 +35,20 @@ impl Metadata {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: None,
nft_path: None,
validator_path: None,
}
}

/// Create a common explorer with /tx, /address, and /token paths
/// Create a common explorer with /tx, /address, /token, and /nft paths
pub fn with_token(name: &'static str, base_url: &'static str) -> Self {
Self {
name,
base_url,
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: Some(TOKEN_PATH),
nft_path: Some(NFT_PATH),
validator_path: None,
}
}
Expand All @@ -57,6 +61,7 @@ impl Metadata {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: None,
nft_path: None,
validator_path: Some(VALIDATOR_PATH),
}
}
Expand All @@ -69,6 +74,7 @@ impl Metadata {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: Some(TOKEN_PATH),
nft_path: Some(NFT_PATH),
validator_path: Some(VALIDATOR_PATH),
}
}
Expand All @@ -81,6 +87,7 @@ impl Metadata {
tx_path: TRANSACTION_PATH,
address_path: ADDRESS_PATH,
token_path: None,
nft_path: None,
validator_path: None,
}
}
Expand All @@ -93,6 +100,7 @@ impl Metadata {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: Some(ASSETS_PATH),
nft_path: None,
validator_path: Some(VALIDATORS_PATH),
}
}
Expand Down Expand Up @@ -125,6 +133,10 @@ impl BlockExplorer for Explorer {
self.config.token_path.map(|path| format!("{}{}/{}", self.config.base_url, path, token))
}

fn get_nft_url(&self, contract: &str, token_id: &str) -> Option<String> {
self.config.nft_path.map(|path| format!("{}{}/{}/{}", self.config.base_url, path, contract, token_id))
}

fn get_validator_url(&self, validator: &str) -> Option<String> {
self.config.validator_path.map(|path| format!("{}{}/{}", self.config.base_url, path, validator))
}
Expand Down Expand Up @@ -169,6 +181,7 @@ mod tests {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: Some(TOKEN_PATH),
nft_path: Some(NFT_PATH),
validator_path: Some(VALIDATOR_PATH),
};
let explorer = Explorer::boxed(config);
Expand All @@ -177,6 +190,7 @@ mod tests {
assert_eq!(explorer.get_tx_url("abc123"), "https://test.com/tx/abc123");
assert_eq!(explorer.get_address_url("addr123"), "https://test.com/address/addr123");
assert_eq!(explorer.get_token_url("token123"), Some("https://test.com/token/token123".to_string()));
assert_eq!(explorer.get_nft_url("contract123", "token123"), Some("https://test.com/nft/contract123/token123".to_string()));
assert_eq!(explorer.get_validator_url("val123"), Some("https://test.com/validator/val123".to_string()));
}

Expand All @@ -188,11 +202,13 @@ mod tests {
tx_path: TRANSACTION_PATH,
address_path: ACCOUNT_PATH,
token_path: None,
nft_path: None,
validator_path: None,
};
let explorer = Explorer::boxed(config);

assert_eq!(explorer.get_token_url("token123"), None);
assert_eq!(explorer.get_nft_url("contract123", "token123"), None);
assert_eq!(explorer.get_validator_url("val123"), None);
}

Expand All @@ -208,23 +224,28 @@ mod tests {

let with_token = Metadata::with_token("WithToken", "https://token.com");
assert_eq!(with_token.token_path, Some(TOKEN_PATH));
assert_eq!(with_token.nft_path, Some(NFT_PATH));
assert_eq!(with_token.validator_path, None);

let with_validator = Metadata::with_validator("WithValidator", "https://validator.com");
assert_eq!(with_validator.token_path, None);
assert_eq!(with_validator.nft_path, None);
assert_eq!(with_validator.validator_path, Some(VALIDATOR_PATH));

let full = Metadata::full("Full", "https://full.com");
assert_eq!(full.token_path, Some(TOKEN_PATH));
assert_eq!(full.nft_path, Some(NFT_PATH));
assert_eq!(full.validator_path, Some(VALIDATOR_PATH));

let transaction_style = Metadata::blockchair("Transaction", "https://transaction.com");
assert_eq!(transaction_style.tx_path, TRANSACTION_PATH);
assert_eq!(transaction_style.address_path, ADDRESS_PATH);
assert_eq!(transaction_style.token_path, None);
assert_eq!(transaction_style.nft_path, None);

let cosmos_style = Metadata::mintscan("Cosmos", "https://cosmos.com");
assert_eq!(cosmos_style.token_path, Some(ASSETS_PATH));
assert_eq!(cosmos_style.nft_path, None);
assert_eq!(cosmos_style.validator_path, Some(VALIDATORS_PATH));
}

Expand All @@ -239,6 +260,7 @@ mod tests {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: None,
nft_path: None,
validator_path: None,
},
)
Expand All @@ -250,6 +272,7 @@ mod tests {
tx_path: TRANSACTION_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(TOKEN_PATH),
nft_path: None,
validator_path: None,
},
);
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/near.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl NearBlocks {
tx_path: TXNS_PATH,
address_path: ADDRESS_PATH,
token_path: None,
nft_path: None,
validator_path: None,
})
}
Expand Down
116 changes: 99 additions & 17 deletions crates/primitives/src/explorers/solana.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,106 @@
use crate::block_explorer::BlockExplorer;
use crate::explorers::metadata::{ACCOUNT_PATH, ADDRESS_PATH, Explorer, Metadata, TOKEN_PATH, TX_PATH};
use crate::explorers::metadata::{ACCOUNT_PATH, ADDRESS_PATH, TOKEN_PATH, TX_PATH};

struct SolanaExplorer {
name: &'static str,
base_url: &'static str,
address_path: &'static str,
token_path: &'static str,
}

impl SolanaExplorer {
fn boxed(
name: &'static str,
base_url: &'static str,
address_path: &'static str,
token_path: &'static str,
) -> Box<dyn BlockExplorer> {
Box::new(Self {
name,
base_url,
address_path,
token_path,
})
}
}

impl BlockExplorer for SolanaExplorer {
fn name(&self) -> String {
self.name.into()
}

fn get_tx_url(&self, hash: &str) -> String {
format!("{}{}/{}", self.base_url, TX_PATH, hash)
}

fn get_address_url(&self, address: &str) -> String {
format!("{}{}/{}", self.base_url, self.address_path, address)
}

fn get_token_url(&self, token: &str) -> Option<String> {
Some(format!("{}{}/{}", self.base_url, self.token_path, token))
}

fn get_nft_url(&self, _contract: &str, token_id: &str) -> Option<String> {
self.get_token_url(token_id)
}
}

pub fn new_solscan() -> Box<dyn BlockExplorer> {
Explorer::boxed(Metadata {
name: "Solscan",
base_url: "https://solscan.io",
tx_path: TX_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(TOKEN_PATH),
validator_path: None,
})
SolanaExplorer::boxed("Solscan", "https://solscan.io", ACCOUNT_PATH, TOKEN_PATH)
}

pub fn new_solana_fm() -> Box<dyn BlockExplorer> {
Explorer::boxed(Metadata {
name: "SolanaFM",
base_url: "https://solana.fm",
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: Some(ADDRESS_PATH),
validator_path: None,
})
SolanaExplorer::boxed("SolanaFM", "https://solana.fm", ADDRESS_PATH, ADDRESS_PATH)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_solscan_urls() {
let explorer = new_solscan();

assert_eq!(explorer.name(), "Solscan");
assert_eq!(
explorer.get_tx_url("ArS7DzeHUA54ccRG12SqEZwt7snQePcanZ77Mkm2KRos"),
"https://solscan.io/tx/ArS7DzeHUA54ccRG12SqEZwt7snQePcanZ77Mkm2KRos"
);
assert_eq!(
explorer.get_address_url("GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"),
"https://solscan.io/account/GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"
);
assert_eq!(
explorer.get_token_url("GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"),
Some("https://solscan.io/token/GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2".to_string())
);
assert_eq!(
explorer.get_nft_url("ignored-contract", "GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"),
Some("https://solscan.io/token/GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2".to_string())
);
}

#[test]
fn test_solana_fm_urls() {
let explorer = new_solana_fm();

assert_eq!(explorer.name(), "SolanaFM");
assert_eq!(
explorer.get_tx_url("ArS7DzeHUA54ccRG12SqEZwt7snQePcanZ77Mkm2KRos"),
"https://solana.fm/tx/ArS7DzeHUA54ccRG12SqEZwt7snQePcanZ77Mkm2KRos"
);
assert_eq!(
explorer.get_address_url("GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"),
"https://solana.fm/address/GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"
);
assert_eq!(
explorer.get_token_url("GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"),
Some("https://solana.fm/address/GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2".to_string())
);
assert_eq!(
explorer.get_nft_url("ignored-contract", "GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2"),
Some("https://solana.fm/address/GvhwZwtV32kYUXUw965CUM3KGPdtBsDwPVpi92brY5R2".to_string())
);
}
}
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/stellar_expert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn new() -> Box<dyn BlockExplorer> {
tx_path: TX_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(ASSET_PATH),
nft_path: None,
validator_path: None,
})
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/subscan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl SubScan {
tx_path: "/extrinsic",
address_path: ACCOUNT_PATH,
token_path: None,
nft_path: None,
validator_path: None,
})
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/sui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn new_sui_scan() -> Box<dyn BlockExplorer> {
tx_path: TX_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(COIN_PATH),
nft_path: None,
validator_path: Some(VALIDATOR_PATH),
})
}
Expand Down
2 changes: 2 additions & 0 deletions crates/primitives/src/explorers/ton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn new_ton_viewer() -> Box<dyn BlockExplorer> {
tx_path: TRANSACTION_PATH,
address_path: "",
token_path: Some(""),
nft_path: None,
validator_path: Some(""),
})
}
Expand All @@ -22,6 +23,7 @@ impl TonScan {
tx_path: TX_PATH,
address_path: ADDRESS_PATH,
token_path: Some("/jetton"),
nft_path: None,
validator_path: Some(ADDRESS_PATH),
})
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/tronscan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl TronScan {
tx_path: TRANSACTION_PATH,
address_path: ADDRESS_PATH,
token_path: Some("/token20"),
nft_path: None,
validator_path: Some(ADDRESS_PATH),
})
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/explorers/xrpscan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl XrpScan {
tx_path: TX_PATH,
address_path: ACCOUNT_PATH,
token_path: Some(ACCOUNT_PATH),
nft_path: None,
validator_path: None,
};
Explorer::boxed(config)
Expand Down
Loading
Loading