use std::sync::LazyLock;
use r402_core::chain::NetworkInfo;
use crate::chain::{CasperChainReference, CasperTokenDeployment, ContractPackageHash};
use crate::motes::CSPR_DECIMALS;
pub static CASPER_NETWORKS: &[NetworkInfo] = &[
NetworkInfo {
name: "casper",
namespace: "casper",
reference: "casper",
},
NetworkInfo {
name: "casper-test",
namespace: "casper",
reference: "casper-test",
},
];
pub const WCSPR_NAME: &str = "Wrapped CSPR";
pub const WCSPR_VERSION: &str = "1";
const WCSPR_TESTNET_PACKAGE: &str =
"3d80df21ba4ee4d66a2a1f60c32570dd5685e4b279f6538162a5fd1314847c1e";
#[allow(
clippy::expect_used,
reason = "hardcoded package hashes are validated at crate build time by the unit tests"
)]
static WCSPR_DEPLOYMENTS: LazyLock<Vec<CasperTokenDeployment>> = LazyLock::new(|| {
vec![CasperTokenDeployment::new(
CasperChainReference::CASPER_TEST,
WCSPR_TESTNET_PACKAGE
.parse::<ContractPackageHash>()
.expect("built-in wCSPR testnet package hash is valid"),
CSPR_DECIMALS,
WCSPR_NAME,
WCSPR_VERSION,
)]
});
#[must_use]
pub fn wcspr_casper_deployments() -> &'static [CasperTokenDeployment] {
&WCSPR_DEPLOYMENTS
}
#[must_use]
pub fn wcspr_casper_deployment(
chain: CasperChainReference,
) -> Option<&'static CasperTokenDeployment> {
WCSPR_DEPLOYMENTS
.iter()
.find(|deployment| deployment.chain_reference == chain)
}
#[derive(Debug, Clone, Copy)]
#[allow(
clippy::upper_case_acronyms,
reason = "WCSPR is a well-known token ticker"
)]
pub struct WCSPR;
#[allow(
clippy::missing_panics_doc,
clippy::expect_used,
reason = "static deployment lookups are infallible for built-in data"
)]
impl WCSPR {
#[must_use]
pub fn on(chain: CasperChainReference) -> Option<&'static CasperTokenDeployment> {
wcspr_casper_deployment(chain)
}
#[must_use]
pub fn all() -> &'static [CasperTokenDeployment] {
wcspr_casper_deployments()
}
#[must_use]
pub fn casper_test() -> &'static CasperTokenDeployment {
wcspr_casper_deployment(CasperChainReference::CASPER_TEST)
.expect("built-in wCSPR deployment for Casper testnet missing")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn network_table_matches_caip2_ids() {
let ids: Vec<String> = CASPER_NETWORKS
.iter()
.map(|net| net.chain_id().to_string())
.collect();
assert_eq!(ids, vec!["casper:casper", "casper:casper-test"]);
}
#[test]
fn every_network_info_maps_to_a_chain_reference() {
for network in CASPER_NETWORKS {
let chain_id = network.chain_id();
assert!(
CasperChainReference::try_from(chain_id).is_ok(),
"network {} has no chain reference",
network.name
);
}
}
#[test]
fn builtin_wcspr_deployment_is_well_formed() {
let deployment = WCSPR::casper_test();
assert_eq!(
deployment.chain_reference,
CasperChainReference::CASPER_TEST
);
assert_eq!(deployment.decimals, CSPR_DECIMALS);
assert_eq!(deployment.name, WCSPR_NAME);
assert_eq!(deployment.version, WCSPR_VERSION);
assert_eq!(deployment.address.to_string(), WCSPR_TESTNET_PACKAGE);
}
#[test]
fn lookup_returns_none_for_chains_without_deployments() {
assert!(WCSPR::on(CasperChainReference::CASPER).is_none());
assert_eq!(WCSPR::all().len(), 1);
}
#[test]
fn deployment_amount_is_exact() {
let amount = WCSPR::casper_test().amount(1_000_000_000);
assert_eq!(amount.amount.inner(), 1_000_000_000);
assert_eq!(amount.amount.to_cspr_string(), "1");
}
}