zingolib 7.0.0

Zingo backend library.
use std::path::PathBuf;

use http::Uri;

use zcash_protocol::{PoolType, ShieldedPool};

use zingo_common_components::protocol::ActivationHeights;
use zingo_test_vectors::seeds;

use crate::config::{ChainType, ClientConfig, WalletConfig};

/// The mainnet indexer these example wallets pin explicitly.
const MAINNET_INDEXER: &str = "https://zec.rocks:443";

/// The testnet indexer these example wallets pin explicitly.
const TESTNET_INDEXER: &str = "https://testnet.zec.rocks:443";
use crate::lightclient::LightClient;
use crate::testutils::paths::get_cargo_manifest_dir;

/// `ExampleWalletNetworkCase` sorts first by Network, then seed, then last saved version.
/// It is public so that any consumer can select and load any example wallet.
#[non_exhaustive]
#[derive(Clone)]
pub enum NetworkSeedVersion {
    /// Regtest seed version
    Regtest(RegtestSeedVersion),
    /// Testnet seed version
    Testnet(TestnetSeedVersion),
    /// Mainnet seed version
    Mainnet(MainnetSeedVersion),
}

#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum MainnetSeedVersion {
    /// this is a mainnet wallet originally called `missing_data_test`
    VillageTarget(VillageTargetVersion),
    /// empty mainnet wallet
    HotelHumor(HotelHumorVersion),
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum VillageTargetVersion {
    /// wallet was last saved in this serialization version
    V28,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum HotelHumorVersion {
    /// wallet was last saved in this serialization version
    Gf0aaf9347,
    /// this wallet was funded with 0.01 sapling fr fr fr
    /// latest version of the wallet, with most up-to-date witness tree. git can tell more about when it was saved.
    Latest,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum TestnetSeedVersion {
    /// this testnet wallet was generated at the beginning of serialization v28 with
    /// --seed "chimney better bulb horror rebuild whisper improve intact letter giraffe brave rib appear bulk aim burst snap salt hill sad merge tennis phrase raise"
    /// with 3 addresses containing all receivers.
    /// including orchard and sapling transactions
    ChimneyBetter(ChimneyBetterVersion),
    /// This is a testnet seed, generated by fluidvanadium at the beginning of owls (this example wallet enumeration)
    MobileShuffle(MobileShuffleVersion),
    /// todo
    GloryGoddess,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum ChimneyBetterVersion {
    /// wallet was last saved in this serialization version
    V26,
    /// wallet was last saved in this serialization version
    V27,
    /// wallet was last saved in this serialization version
    V28,
    /// wallet was last saved at this commit
    Latest,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum MobileShuffleVersion {
    /// wallet was last saved by the code in this commit
    Gab72a38b,
    /// this wallet was synced in this version. does it have a bunch of taz scattered around different addresses?
    G93738061a,
    /// most recent chain state added to the wallet
    Latest,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum RegtestSeedVersion {
    /// this is a regtest wallet originally called `old_wallet_reorg_test_wallet`
    HospitalMuseum(HospitalMuseumVersion),
    /// this is a regtest wallet originally called `v26/sap_only`
    AbandonAbandon(AbandonAbandonVersion),
    /// another regtest wallet
    AbsurdAmount(AbsurdAmountVersion),
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum HospitalMuseumVersion {
    /// wallet was last saved in this serialization version
    V27,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum AbandonAbandonVersion {
    /// wallet was last saved in this serialization version
    V26,
}
#[allow(missing_docs)] // described in parent enum
#[non_exhaustive]
#[derive(Clone)]
pub enum AbsurdAmountVersion {
    /// existing receivers?
    OrchAndSapl,
    /// existing receivers?
    OrchOnly,
}

impl NetworkSeedVersion {
    /// Loads wallet from test wallet files.
    // TODO: improve with macro
    #[must_use]
    pub fn example_wallet_path(&self) -> PathBuf {
        match self {
            NetworkSeedVersion::Regtest(seed) => match seed {
                RegtestSeedVersion::HospitalMuseum(version) => match version {
                    HospitalMuseumVersion::V27 => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/regtest/hmvasmuvwmssvichcarbpoct/v27/zingo-wallet.dat",
                    ),
                },
                RegtestSeedVersion::AbandonAbandon(version) => match version {
                    AbandonAbandonVersion::V26 =>  get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/regtest/aaaaaaaaaaaaaaaaaaaaaaaa/v26/zingo-wallet.dat"
                    ),
                },
                RegtestSeedVersion::AbsurdAmount(version) => match version {
                    AbsurdAmountVersion::OrchAndSapl => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/regtest/aadaalacaadaalacaadaalac/orch_and_sapl/zingo-wallet.dat",
                    ),
                    AbsurdAmountVersion::OrchOnly => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/regtest/aadaalacaadaalacaadaalac/orch_only/zingo-wallet.dat",
                    ),
                },
            },
            NetworkSeedVersion::Testnet(seed) => match seed {
                TestnetSeedVersion::ChimneyBetter(version) => match version {
                    ChimneyBetterVersion::V26 => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/cbbhrwiilgbrababsshsmtpr/v26/zingo-wallet.dat",
                    ),
                    ChimneyBetterVersion::V27 => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/cbbhrwiilgbrababsshsmtpr/v27/zingo-wallet.dat",
                    ),
                    ChimneyBetterVersion::V28 => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/cbbhrwiilgbrababsshsmtpr/v28/zingo-wallet.dat",
                    ),
                    ChimneyBetterVersion::Latest => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/cbbhrwiilgbrababsshsmtpr/latest/zingo-wallet.dat",
                    ),
                },
                TestnetSeedVersion::MobileShuffle(version) => match version {
                    MobileShuffleVersion::Gab72a38b => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/mskmgdbhotbpetcjwcspgopp/Gab72a38b/zingo-wallet.dat",
                    ),
                    MobileShuffleVersion::G93738061a => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/mskmgdbhotbpetcjwcspgopp/G93738061a/zingo-wallet.dat",
                    ),
                    MobileShuffleVersion::Latest => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/mskmgdbhotbpetcjwcspgopp/latest/zingo-wallet.dat",
                    ),
                },
                TestnetSeedVersion::GloryGoddess => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/testnet/glory_goddess/latest/zingo-wallet.dat",
                    ),
            },
            NetworkSeedVersion::Mainnet(seed) => match seed {
                MainnetSeedVersion::VillageTarget(version) => match version {
                    VillageTargetVersion::V28 => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/mainnet/vtfcorfbcbpctcfupmegmwbp/v28/zingo-wallet.dat",
                    ),
                },
                MainnetSeedVersion::HotelHumor(version) => match version {
                    HotelHumorVersion::Gf0aaf9347 => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/mainnet/hhcclaltpcckcsslpcnetblr/gf0aaf9347/zingo-wallet.dat",
                    ),
                    HotelHumorVersion::Latest => get_cargo_manifest_dir().join("src/wallet/disk/testing/examples/mainnet/hhcclaltpcckcsslpcnetblr/latest/zingo-wallet.dat",
                    ),
                },
            },
        }
    }

    /// Loads light client from test wallet files.
    /// - Reads the committed wallet file. The client starts offline: no indexer is dialed.
    pub async fn load_example_wallet(&self) -> LightClient {
        let path = self.example_wallet_path();
        let config = ClientConfig::builder()
            .set_chain_type(self.chain_type())
            .set_wallet_name(path.file_name().unwrap().to_string_lossy().to_string())
            .set_wallet_dir(path.parent().unwrap().to_path_buf())
            .set_wallet_config(WalletConfig::Read)
            .build()
            .unwrap();
        LightClient::new(config, false).await.unwrap()
    }

    /// - Reads the committed wallet file and dials the network's indexer.
    /// - Panics for a regtest example, which has no live network.
    pub async fn load_example_wallet_online(&self) -> LightClient {
        let uri = self
            .indexer_uri()
            .expect("a regtest example wallet has no live network to dial");
        let mut client = self.load_example_wallet().await;
        client.set_indexer_uri(uri).await.unwrap();
        client
    }

    fn chain_type(&self) -> ChainType {
        match self {
            NetworkSeedVersion::Regtest(_) => ChainType::Regtest(ActivationHeights::default()),
            NetworkSeedVersion::Testnet(_) => ChainType::Testnet,
            NetworkSeedVersion::Mainnet(_) => ChainType::Mainnet,
        }
    }

    fn indexer_uri(&self) -> Option<Uri> {
        let indexer = match self {
            NetworkSeedVersion::Regtest(_) => return None,
            NetworkSeedVersion::Testnet(_) => TESTNET_INDEXER,
            NetworkSeedVersion::Mainnet(_) => MAINNET_INDEXER,
        };
        Some(indexer.parse::<Uri>().unwrap())
    }
    /// picks the seed (or ufvk) string associated with an example wallet
    #[must_use]
    pub fn example_wallet_seed(&self) -> String {
        match self {
            NetworkSeedVersion::Regtest(seed) => match seed {
                RegtestSeedVersion::HospitalMuseum(_) => {
                    seeds::HOSPITAL_MUSEUM_SEED.to_string()
                },
                RegtestSeedVersion::AbandonAbandon(_) => {
                    seeds::ABANDON_ART_SEED.to_string()
                },
                RegtestSeedVersion::AbsurdAmount(_) => {
                    "absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice comic".to_string()
                }
            },
            NetworkSeedVersion::Testnet(seed) => match seed {
                TestnetSeedVersion::ChimneyBetter(
                    _,
                ) => seeds::CHIMNEY_BETTER_SEED.to_string(),
                TestnetSeedVersion::MobileShuffle(
                    _,
                ) => "mobile shuffle keen mother globe desk bless hub oil town begin potato explain table crawl just wild click spring pottery gasp often pill plug".to_string(),
                TestnetSeedVersion::GloryGoddess => "glory goddess cargo action guilt ball coral employ phone baby oxygen flavor solid climb situate frequent blade pet enough milk access try swift benefit".to_string(),
            },
            NetworkSeedVersion::Mainnet(seed) => match seed {
                MainnetSeedVersion::VillageTarget(
                     _,
                ) => "village target fun course orange release female brain cruise birth pet copy trouble common fitness unfold panther man enjoy genuine merry write bulb pledge".to_string(),
                MainnetSeedVersion::HotelHumor(
                     _,
                ) => "hotel humor crunch crack language awkward lunar term priority critic cushion keep coin sketch soap laugh pretty cement noodle enjoy trip bicycle list return".to_string()
            }
        }
    }
    /// picks the first receiver associated with an example wallet
    #[must_use]
    pub fn example_wallet_address(&self, pool: PoolType) -> String {
        match self {
            NetworkSeedVersion::Regtest(seed) => match seed {
                RegtestSeedVersion::HospitalMuseum(_) => {
                    match pool {
                        PoolType::Transparent => {"tmFLszfkjgim4zoUMAXpuohnFBAKy99rr2i".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"uregtest1ue949txhf9t2z6ldg8wc6s5t439t2hu55yh9l58gc23cmxthths836nxtpyvhpkrftsp2jnnp9eadtqy2nefxn04eyxeu8l0x5kk8ct9".to_string()},
                    }
                }
                RegtestSeedVersion::AbandonAbandon(_) => {
                    match pool {
                        PoolType::Transparent => {"tmBsTi2xWTjUdEXnuTceL7fecEQKeWaPDJd".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"uregtest1h8fnf3vrmswwj0r6nfvq24nxzmyjzaq5jvyxyc2afjtuze8tn93zjqt87kv9wm0ew4rkprpuphf08tc7f5nnd3j3kxnngyxf0cv9k9lc".to_string()},
                    }
                }
                RegtestSeedVersion::AbsurdAmount(_) => {
                    match pool {
                        PoolType::Transparent => {"tmS9nbexug7uT8x1cMTLP1ABEyKXpMjR5F1".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"uregtest1s79x7etgyc7yl5tpw3vf2k6xa5qqk30de670p68c9tes79p2lkfm0vpy2u34x6wrwaa2fsxayjvz9dshrv92dur3h694v7sqnsgac028".to_string()},
                    }
                }
            },
            NetworkSeedVersion::Testnet(seed) => match seed {
                TestnetSeedVersion::ChimneyBetter(_) => {
                    match pool {
                        PoolType::Transparent => {"tmYd5GP6JxUxTUcz98NLPumEotvaMPaXytz".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"utest1f7hprvzygjeq6gtyh2splf0qq3ug70krvq44z40d7lg590u2dwg59l8we9v2mdpk72llg5wd9cat68ur0pdrmyx8fs54x6asy5z86elr".to_string()},
                    }
                }
                TestnetSeedVersion::MobileShuffle(_) => {
                    match pool {
                        PoolType::Transparent => {"tmEVmDAnveCakZkvV4a6FT1TfYApTv937E7".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"utest1uuwsmtfxnssw7uu664gevkz8xydtcwmt6u0gns95n6pr0vetdpm6mz6ltczk68c0cp8svevr6j4xkps2wdvcrf0gy0lvnfry8qn7gvjc".to_string()},
                    }
                }
                TestnetSeedVersion::GloryGoddess => {
                    match pool {
                        PoolType::Transparent => {"tmF7QpuKsLF7nsMvThu4wQBpiKVGJXGCSJF".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"utest1dmu08vg5wt5m9w0ejwgeqdndzzkfka7c94heuz5llxv5vx4lhcethmm6p5ean3wcj8l0m6tf8k8cau9r636gq7sxq3wa6zey2sysfteh".to_string()},
                    }
                }
            },
            NetworkSeedVersion::Mainnet(seed) => match seed {
                MainnetSeedVersion::VillageTarget(_) => {
                    match pool {
                        PoolType::Transparent => {
                    "t1P8tQtYFLR7TWsqtauc71RGQdqqwfFBbb4".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"u1d6whpxpf9l7k7z9ce85w4w3wgfv0y3h5lm25g7ae7wqryqcy9zf7xwd2k6gpqzhat9den3c8ezk797gvdmrhm6dtuldz3wpj5yf27jd3".to_string()},
                    }
                }
                MainnetSeedVersion::HotelHumor(_) => {
                    match pool {
                        PoolType::Transparent => {"t1XnsupYhvhSDSFJ4nzZ2kADhLMR22wg35y".to_string()},
                        PoolType::Shielded(ShieldedPool::Sapling) => {panic!("no sapling receiver in default unified address")},
                        PoolType::Shielded(ShieldedPool::Orchard) | PoolType::IRONWOOD => {"u17923s4jdmkcjm8ek8t5elhuejlv8wfhwdqxqewk9meqfztmdyatnpxpcudc22qv2625gcp0uadrnf7ggduwutp065vue9m7ekgqxk9eg".to_string()},
                    }
                }
            },
        }
    }
}