//! Ghost chain configuration.

use codec::Encode;

use ghost_slow_clap::sr25519::AuthorityId as SlowClapId;
use primitives::{AccountId, AccountPublic};
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
use grandpa_primitives::AuthorityId as GrandpaId;
use babe_primitives::AuthorityId as BabeId;
#[cfg(feature = "casper-native")]
use pallet_staking::Forcing;

#[cfg(feature = "casper-native")]
use casper_runtime as casper;
#[cfg(feature = "casper-native")]
use casper_runtime_constants::currency::{CSPR, STRH};
use sc_chain_spec::ChainSpecExtension;
#[cfg(feature = "casper-native")]
use sc_chain_spec::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::IdentifyAccount;
#[cfg(feature = "casper-native")]
use sp_runtime::Perbill;
#[cfg(feature = "casper-native")]
use telemetry::TelemetryEndpoints;

#[cfg(feature = "casper-native")]
const CASPER_TELEMETRY_URL: &str = "wss://telemetry.ghostchain.io/submit/";

#[cfg(feature = "casper-native")]
const DEFAULT_PROTOCOL_ID: &str = "cspr";

/// Node `ChainSpec` extensions.
///
/// Additional parameters for some substrate core modules,
/// customizable from the chain spec.
#[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)]
#[serde(rename_all = "camelCase")]
pub struct Extensions {
    /// Block number with known hashes.
    pub fork_blocks: sc_client_api::ForkBlocks<primitives::Block>,
    /// Known bad block hashes.
    pub bad_blocks: sc_client_api::BadBlocks<primitives::Block>,
    /// The light sync state.
    /// This value will be set by the `sync-state rpc` implementation.
    pub light_sync_state: sc_sync_state_rpc::LightSyncStateExtension,
}

// Generic chain spec, in case when we don't have the native runtime.
pub type GenericChainSpec = sc_service::GenericChainSpec<(), Extensions>;

/// The `ChainSpec` parametrized for the ghost runtime.
#[cfg(feature = "casper-native")]
pub type CasperChainSpec = sc_service::GenericChainSpec<(), Extensions>;

#[cfg(not(feature = "casper-native"))]
pub type CasperChainSpec = GenericChainSpec;

pub fn casper_config() -> Result<CasperChainSpec, String> {
   CasperChainSpec::from_json_bytes(&include_bytes!("../chain-specs/casper.json")[..])
}

#[cfg(feature = "casper-native")]
fn casper_session_keys(
    babe: BabeId,
    grandpa: GrandpaId,
    authority_discovery: AuthorityDiscoveryId,
    slow_clap: SlowClapId,
) -> casper::opaque::SessionKeys {
    casper::opaque::SessionKeys {
        babe,
        grandpa,
        authority_discovery,
        slow_clap,
    }
}


pub fn casper_chain_spec_properties() -> serde_json::map::Map<String, serde_json::Value> {
    serde_json::json!({
        "ss58Format": 1996,
        "tokenDecimals": 18,
        "tokenSymbol": "CSPR",
    })
    .as_object()
    .expect("Map given; qed")
    .clone()
}

/// Helper function to generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
    TPublic::Pair::from_string(&format!("//{}", seed), None)
        .expect("static values are valid; qed")
        .public()
}

/// Helper function to generate account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
    AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
    AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}

/// Helper function to generate stash, controller and session key from seed
pub fn generate_authority_keys_from_seed(
    seed: &str,
) -> (
    AccountId,
    AccountId,
    BabeId,
    GrandpaId,
    AuthorityDiscoveryId,
    SlowClapId,
) {
    let keys = get_authority_keys_from_seed(seed);
    (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5)
}

/// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(
    seed: &str,
) -> (
    AccountId,
    AccountId,
    BabeId,
    GrandpaId,
    AuthorityDiscoveryId,
    SlowClapId,
) {
    (
        get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
        get_account_id_from_seed::<sr25519::Public>(seed),
        get_from_seed::<BabeId>(seed),
        get_from_seed::<GrandpaId>(seed),
        get_from_seed::<AuthorityDiscoveryId>(seed),
        get_from_seed::<SlowClapId>(seed),
    )
}

#[cfg(feature = "casper-native")]
fn casper_testnet_accounts() -> Vec<AccountId> {
    vec![
        get_account_id_from_seed::<sr25519::Public>("Alice"),
        get_account_id_from_seed::<sr25519::Public>("Bob"),
        get_account_id_from_seed::<sr25519::Public>("Charlie"),
        get_account_id_from_seed::<sr25519::Public>("Dave"),
        get_account_id_from_seed::<sr25519::Public>("Eve"),
        get_account_id_from_seed::<sr25519::Public>("Feride"),
        get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
        get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
        get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
        get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
        get_account_id_from_seed::<sr25519::Public>("Feride//stash"),
    ]
}

#[cfg(feature = "casper-native")]
fn casper_testnet_evm_accounts() -> Vec<(AccountId, u128, u8)> {
    vec![
        // 01c928771aea942a1e7ac06adf2b73dfbc9a25d9eaa516e3673116af7f345198
        (get_account_id_from_seed::<sr25519::Public>("1A69d2D5568D1878023EeB121a73d33B9116A760"), 1337 * CSPR, 1), 
        // b19a435901872f817185f7234a1484eae837613f9d10cf21927a23c2d8cb9139
        (get_account_id_from_seed::<sr25519::Public>("2f86cfBED3fbc1eCf2989B9aE5fc019a837A9C12"), 1337 * CSPR, 2), 
        // d3baf57b74d65719b2dc33f5a464176022d0cc5edbca002234229f3e733875fc
        (get_account_id_from_seed::<sr25519::Public>("e83f67361Ac74D42A48E2DAfb6706eb047D8218D"), 69   * CSPR, 3), 
        // c4683d566436af6b58b4a59c8f501319226e85b21869bf93d5eeb4596d4791d4
        (get_account_id_from_seed::<sr25519::Public>("827ee4ad9b259b6fa1390ed60921508c78befd63"), 69   * CSPR, 4), 
    ]
}

#[cfg(feature = "casper-native")]
fn casper_testnet_evm_networks() -> Vec<(u32, Vec<u8>)> {
    vec![
        (1, ghost_networks::NetworkData { 
            chain_name: "ethereum-mainnet".into(), 
            default_endpoint: "https://nd-422-757-666.p2pify.com/0a9d79d93fb2f4a4b1e04695da2b77a7/".into(),
            finality_delay: 40u64,
            rate_limit_delay: 1u64,
            block_distance: 50u64,
            network_type: ghost_networks::NetworkType::Evm,
            gatekeeper: "0x4d224452801aced8b2f0aebe155379bb5d594381".into(),
            topic_name: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".into(),
            incoming_fee: 0u32,
            outgoing_fee: 0u32,
        }.encode()),
        (56, ghost_networks::NetworkData { 
            chain_name: "bnb-mainnet".into(), 
            default_endpoint: "https://bsc-mainnet.core.chainstack.com/35848e183f3e3303c8cfeacbea831cab/".into(),
            finality_delay: 20u64,
            rate_limit_delay: 1u64,
            block_distance: 50u64,
            network_type: ghost_networks::NetworkType::Evm,
            gatekeeper: "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82".into(),
            topic_name: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".into(),
            incoming_fee: 0u32,
            outgoing_fee: 0u32,
        }.encode())
    ]
}

/// Helper function to create casper `GenesisConfig` for testing
#[cfg(feature = "casper-native")]
pub fn testnet_config_genesis(
    initial_authorities: Vec<(
        AccountId,
        AccountId,
        BabeId,
        GrandpaId,
        AuthorityDiscoveryId,
        SlowClapId,
    )>,
    endowed_accounts: Option<Vec<AccountId>>,
    ghost_accounts: Option<Vec<(AccountId, u128, u8)>>,
    evm_networks: Option<Vec<(u32, Vec<u8>)>>,
) -> serde_json::Value {
    let endowed_accounts: Vec<AccountId> = endowed_accounts
        .unwrap_or_else(casper_testnet_accounts);

    let ghost_accounts: Vec<(AccountId, u128, u8)> = ghost_accounts
        .unwrap_or_default();

    let evm_networks: Vec<(u32, Vec<u8>)> = evm_networks
        .unwrap_or_default();

    const ENDOWMENT: u128 = 1_000 * CSPR;
    const STASH: u128 = 500 * CSPR;

    serde_json::json!({
        "balances": {
            "balances": endowed_accounts
                .iter()
                .map(|k| (k.clone(), ENDOWMENT))
                .chain(ghost_accounts
                    .iter()
                    .map(|k| (k.0.clone(), k.1.clone())))
                .collect::<Vec<_>>(),
        },
        "session": {
            "keys": initial_authorities
                .iter()
                .map(|x| {
                    (
                        x.0.clone(),
                        x.0.clone(),
                        casper_session_keys(
                            x.2.clone(),
                            x.3.clone(),
                            x.4.clone(),
                            x.5.clone(),
                        ),
                    )
                })
                .collect::<Vec<_>>(),
        },
        "staking": {
            "validatorCount": initial_authorities.len() as u32,
            "minimumValidatorCount": 1,
            "invulnerables": initial_authorities
                .iter()
                .map(|x| x.0.clone())
                .collect::<Vec<_>>(),
            "forceEra": Forcing::NotForcing,
            "slashRewardFraction": Perbill::from_percent(10),
            "stakers": initial_authorities
                .iter()
                .map(|x| (x.0.clone(), x.0.clone(), STASH, casper::StakerStatus::<AccountId>::Validator))
                .collect::<Vec<_>>(),
        },
        "babe": {
            "epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG),
        },
        "ghostNetworks": {
            "networks": evm_networks,
        },
        "ghostClaims": {
            "total": ghost_accounts.iter().fold(0, |acc, k| acc + k.1),
            "membersAndRanks": ghost_accounts
                .iter()
                .map(|k| (k.0.clone(), k.2.clone()))
                .collect::<Vec<_>>(),
        },
    })
}

#[cfg(feature = "casper-native")]
fn casper_staging_config_genesis() -> serde_json::Value {
    use hex_literal::hex;
    use sp_core::crypto::UncheckedInto;

    // Endowments for the whales from previous testnet.
    let whales_endowments = [
        // sfHXFVNvLVp8uSZauMyMijqXfoods8kkkik2MKnmr5MTdsweh
        (hex!["a8ab31b36aae0dc29d2b92714cee75ee2784037c6f150d759d9aa757ab5a4666"].into(), 25 * CSPR),
        // sfEtW9ijdwbU17oderTmwseMV84c7c9Xi1JW7T94rBbYKMMZq
        (hex!["342c0035531136ff50d8488eb4d4772dfd10e565f6a5d28c7298b354d33f2dfe"].into(), 14 * CSPR),
        // sfJtE2J5yVQBHdzwmXhzTwQZLtS853MFkUVYv5AfnB7TEVp2E
        (hex!["e4e6a493d23633bf72b16ead89ab1451611b08311a9a49cc874a92e6ac4f5b1d"].into(), 31 * CSPR),
        // sfFf48EnVLjD4wMecZh7meP5RWwYXZr54QiW2xQyPKPjxsxNo
        (hex!["56266f27a02869f9498a113cbd4d1507ae5f4b8c91a6b8ccecda3331c21fd67f"].into(), 6 * CSPR),
        // sfHxHVmMKZfUUzXRzKrV3oXSSynG1uAJ7c6dhFSq4CwE8qLn3
        (hex!["bbc31594a2338e91c248aba474d892f41811a072c7e7c692fcae07fdb398b89f"].into(), 3 * CSPR),
        // sfGvSkgfv99AndiEuhmL6t49ekbb2og2aYVRisAeNMPHueACW
        (hex!["8e1f85cc6bb89182bc473859287b82fc2b9c89f461431090c2246a1a8d92d911"].into(), 14 * CSPR),
        // sfHfByscdWfjzQNXc5g2q2ScMhop5pr5TiqiZosKxtMit1bRy
        (hex!["aeb95893ab118bf02f5cd80ebab71ba58490c645e4302773fdc90b659f5c5e22"].into(), 11 * CSPR),
        // sfGh1jtdTwWEco2N6cymxKgaoAJwYFMj2K2tdEbuML5LjUprc
        (hex!["83e120fa3994efedc51092a8d90882803997f39f552a37699e3acb06c1f8158d"].into(), 28 * CSPR),
        // sfJHvJDgdKdo1ZFXB146jhKVgngDrDeKTKF3GV5Eyvg1tJqTq
        (hex!["cabca1450cbdc5769fa8f7b80d5bfd00df35b65613d8694e02517c9415fc5462"].into(), 12 * CSPR),
        // sfE4SvLvh66FSThDnrTx5Qf5vHNCmBkrAJy8Zt8pMPN8h6dzw
        (hex!["0f85589e37f3c0859ba7c055dec527a63796d6285b73cf8bd4657da052ff893c"].into(), 2 * CSPR),
        // sfHJF1dYfzCpjJ8QHRBexNMfvSfsJvE75eCzgosrB6PwFXmpz
        (hex!["9ebf64b6bc73baf1428da1cfcf36fde9695be0a56a855ddabb5612a70b10e447"].into(), 6 * CSPR),
        // sfEEixqLWYct7au1PWkQAKbyso5VQhrgXQ2RXVW5TjcBm3vZ6
        (hex!["175bce3674e24ec942112d91df594ba551b329ae7183b0faaef79fa051a85948"].into(), 21 * CSPR),
        // sfH5nCFu2wNXnfD1Fic1weyLHncxHb7qpa8yXXQuNbQRUm9HH
        (hex!["953e2cdbf7a66e34c50c51d199ad8970b1b2233da5604eb79a1de8d277c03061"].into(), 10 * CSPR),
        // sfJnVLd4PMfoABtQiPmifeqkpQQKoV4wbXyAzhXKdSDHfi1bY
        (hex!["e086ba892126243d6ef1c2b9132790e4455a3b1271baac8033306d55c8473af4"].into(), 30 * CSPR),
        // sfECamJamifU5XyHH27ekuWY3MHAwj1z3rDcV2rpWdeGdAe2Y
        (hex!["15b9b710a589968804e6e00f2ccb576ded431627a733b7f9fa0845f59e73f5cc"].into(), 31 * CSPR),
        // sfEAhZrKxxChBR5SHQML6gNDJCK2FTMnRZZ2s2KVCFRxqFFTG
        (hex!["144a1fa97fdba679efd2a36696a0d40f585b649143bb7da5cbd7458ea4a0f674"].into(), 2 * CSPR),
        // sfDrDchmoxEfzyyPFWGX2fekP4mic99D6inhPnRvwokRZCbv5
        (hex!["06319d9539108995233c48032bda04d50115fe829a2c4b5b23e54a4d17188606"].into(), 14 * CSPR),
        // sfEb6NRc4ZbcuWUGJAnBkvEoacoXLbHZSM1asLpHiXqeY6YkE
        (hex!["26e4c66dab5d9df3cb196ce320314e2565489f7d56b9868299a68cc4a1b4c917"].into(), 24 * CSPR),
        // sfHfQMwpzNaA3D1uRGrzNPwZDeFbdXQDBJMay1oFDmD7C2RLn
        (hex!["aee305cf2e015ef860c96815bb34ff9ac7df36db95f0587b6ded75218ae0d526"].into(), 22 * CSPR),
        // sfKPnkuxV9u7AEk6bqU4i83NpAeG5w6VjcXYER5yfoojkkcN4
        (hex!["fb72f46bd61ce821d12f5bdd6dc587afe5ae5821632b7e4b09464ea9e04111e3"].into(), 4 * CSPR),
        // sfJGyU6k2gPVhmQJvgtY3iaVsakKQuD56jdgKZTGRLwjkHcbQ
        (hex!["ca040e9167e0e7675ea2163506706cb7883a601a9ece1ba702fd253446f69e5d"].into(), 19 * CSPR),
        // sfF8tAs7Z9R3GU8AnWgHEubxbwGt4zk7V6gSBeJJSqvt1xs8e
        (hex!["3f238fbe70fdf9df12ed42416be91fa556802e7be7ea43c4de33314f5fb2da53"].into(), 22 * CSPR),
        // sfHtQ3XxjAc3fbr4rxnx5P5ejV7LPXnN8nXwxevJ5MZwPJFCa
        (hex!["b8cc24f449bd14c9903431b710842e1398a83d2ced33c5ea8fa4b75461db2f1f"].into(), 28 * CSPR),
        // sfG5KDhmeKs6jXC2Jt1otffwHQyLR58dMGHwJCizUJHr4a7pU
        (hex!["68a722b719350846a1f5a83143e01fdf18422d0d3d489877510062498ba74e5b"].into(), 17 * CSPR),
        // sfH28MB4HFrE8YmtAcj95oTyMsQ9GgYWqxVtisWPqV5SwSMVS
        (hex!["9275098141352f7e4fb3a4be9b2e50269947b7f54ecf2a493454955dd327274a"].into(), 28 * CSPR),
        // sfEBNrjumQ8GLJTxeu3HvUDqHki3UxHCoSzg1x8SDJkfWfhWc
        (hex!["14ce63bf285ad88594a93af2f1b8fd822c4db73030ae0783836083201876cb71"].into(), 14 * CSPR),
        // sfFMYowKRoik3N9tYoSaPZ4vGPaPrDaezXiTVGZUBGWEwSKWQ
        (hex!["48cc93d26f56df01cbd642e2d6eca745a9e2b84616e7f3b405411963c9aefa2f"].into(), 11 * CSPR),
        // sfHPg4uVcq3s3TnfqHcsT6nEmeKJuNiJCW2eHk8Uk5aRfS7jr
        (hex!["a2e3f7cfc7d8b7992a17b7aa8a85b47f1e0d254f3f0b760764f79af5a8349b33"].into(), 22 * CSPR),
        // sfFo97CYcVqhjeiQiu6umcDggkNRWNjNu3XA6pU67F2C4Zs7g
        (hex!["5c512b2cdb7da57ac056d6573ae3d1ae027bcec1b3b3d4dd79dc50160b24101b"].into(), 3 * CSPR),
        // sfGxyWHjTMDVfmScYXjRFwXuVLyPj6XB8nzVjeZTLZ8RQkXQU
        (hex!["900d88832e0748670c2358f2238bd34aaf49e070aa41aba84d931a0d1fef0978"].into(), 15 * CSPR),
        // sfJHHLnAf9kbZz1PL4ESDpEMuAw7GXfFigC9wJD7ZArqRPwVG
        (hex!["ca4039b68f9924c12399808da77247f2f45b0a9e397de94a33104c610cd8287f"].into(), 1 * CSPR),
        // sfHqoR2AnJgWckgFY4HE2p5SK5gf6mUZGCXV5S3Ck7mnpTWps
        (hex!["b6d11481813a6968a1d056794e6f0b85408480c5e8a6056769fbec9b5424314d"].into(), 18 * CSPR),
        // sfJCVDhbVQzg7Y9JTm9mYiowUg2SuGQLLKGPwtstLVgtrcnmu
        (hex!["c697fbb0ecf8069a0f88292d0a2097ba24b8c6998d04d21a02d92f6a23a65b43"].into(), 11 * CSPR),
        // sfFFc7sBndJG1sZpxXfzti9K4Z7cNNfW8EQtEzsX9B1BWXoBv
        (hex!["44443e9670b7f6decd4da7b042b6c9f740bd6b82e564fd51c1453fa442f0192f"].into(), 15 * CSPR),
        // sfJbxCLF7tdMQRqzVgTiGyJQ2V2tEJXeC9pmeZqRaH3kNqYFA
        (hex!["d87d702b99b8b3d58d8a48e5d750f40338b3a3d43fab09c23c50036226ba5325"].into(), 28 * CSPR),
        // sfDrr9Vh9k3hC8JnpN4BG15z5yJPfMhHuPwFsZrd3S62b5U2Y
        (hex!["06ac96e99519ae0a38f2475edfda3e432d3ae8d1f889a82e9ded1f1ccc850505"].into(), 15 * CSPR),
        // sfJq7W4AboVKNgeG33y2oCE5o6h3eJaG6cyoKwtqjTkjSZXs4
        (hex!["e286f428cd368ae7249d4ea76ad17df9350b0dcb437eadbf60053177769fbc5a"].into(), 14 * CSPR),
        // sfG8ERVrJaoaJZdxT8tt9ZBRH4y1q9RHkyW1juiQBFjfqNm5s
        (hex!["6ae0b990e482c499d93382e6183c0d2f3e8228e603de7c154ffb93e2299f152a"].into(), 14 * CSPR),
        // sfG7q2arcyPyzNWrEZRoFvrf6go5PuhwofYVcthR3Mpu8dHgz
        (hex!["6a91f855ff00e83c9b03cc222291cd6d098be0318eb60b88e6c167ce9e513a50"].into(), 11 * CSPR),
        // sfFoee91wxv2u9LRFxCv9pzpM9L9YWGX2CPZveLFWbntrq6zd
        (hex!["5cb4964925c2061492b88ff8daea2804b5770c044946c4ff0ac5a170eab1422c"].into(), 26 * CSPR),
        // sfGkHJcQDaqeagPGrpaNFKR1kdRShUZH4Ec8iYMj6kyH8M2Tg
        (hex!["865f4233b54d0903f5fdad05b0ec715b0ad9613fc69df18df4a013d3c7d3ab73"].into(), 2 * CSPR),
        // sfFXJNrot6ou3UAmcynzSrD1RZnZzyhKM4gdMPfuDLUhCPyDs
        (hex!["503c72a0f2c549a62d876dea81aa2e597b88503fa639ab0e9b65db599785f61d"].into(), 26 * CSPR),
        // sfJyW71FYeFRb3YSQSVJAEp3CjPpNcUmzkw7riKMSkCiBEAs6
        (hex!["e8ed0109c607d78aec9d8aa3575a565e34d65b399a5bd0e0102032d807ea0975"].into(), 5 * CSPR),
        // sfKCXSvdcMTWyJDXDdZ2QP88ZsHDiwnGPfDVRPetf6KQfDAKY
        (hex!["f2dbb77f0f922e5e92d98de7d43612d2f0b0d503aff20607d6c771fe8ee4a623"].into(), 31 * CSPR),
        // sfJjXxYZNuXNirgQFE4MxuJ1w2ekxXHvXtowqUqEN52BNRryW
        (hex!["de45cf59f588af5ee252c0ee0c805be8fa1ce172f8a6187d3b63dce1dc9c0b60"].into(), 8 * CSPR),
        // sfGZf5wgfaLUq3h3JwHgZ52Fg2P27JYn2tSCgjosp4gL2Mdpx
        (hex!["7e44e1ede822621cc9f618480433fe002bb8edde02d2fcd4fcf406409e154e68"].into(), 28 * CSPR),
        // sfETREDdpH8vyT6zHEfcF5qdJhNw8iJVFeSfspKHv2BeUGQg5
        (hex!["210a4b979e39c3136be105df1974fc036f4fe9b035936c149bdb94a3f4820487"].into(), 6 * CSPR),
        // sfHA9NkB5Bb5hgt1f58jf1UminCdrmyu94VGoKB3jo9YRoPjW
        (hex!["98927535310e1b910ca19860e1539a15c5dc02df780a66a22f5796cec3768812"].into(), 12 * CSPR),
        // sfJeYC8LPe41yBP8WptgSzkYgfM39y3derRV4YeYXkpEysT7b
        (hex!["da765f0ad9bedffdc9aa88da6fdacf4afa4463395785b6e03acb0811395a8f5d"].into(), 20 * CSPR),
        // sfEu7ZzgjwEuhS1EkebXfkvH3wMyxpSgcvH8btDi6EMqG4goQ
        (hex!["34a33af049f4f1b65d518e51f38c7afb0cd973c649588808b2ba0211f4ada535"].into(), 5 * CSPR),
        // sfHZx1bZK6aoJKfQ1XQfpRD5VZBXZM1uREGcBsnKJdTZDnDod
        (hex!["aaba173e1cd257c1ba67afbed0fbf2c4aadbfac329f129f12c4941b8b6bc5865"].into(), 5 * CSPR),
        // sfJHhyq2r19nHEbKbVn3NEWqkDWnK53rU9mpRVPEYh7dqkCwU
        (hex!["ca932abf1648393d722ad23c2cd97515a436840d905d3dd2b4d1913989abbc12"].into(), 2 * CSPR),
        // sfE8Hv37BNfZfdj6aKC8XuBPQRG6eLRJPuRqEmrCfPGF4F7Ag
        (hex!["1274036453f19a410d99cd7a13235422062ff5b0d2dbd608d87ad33b9b7b544c"].into(), 17 * CSPR),
        // sfJHHALMCEmBTJHEdHkgMbUt2XMFP4K2AcYPiwgtz429YUqWv
        (hex!["ca3f9e8480f200b6afe9661cb96a30259fc88b947c3ab466bd2b8e902a859719"].into(), 2 * CSPR),
        // sfKTaDy3Yw6eXz4GFfXLRx9LnDf8qEt4JpqnPJc8bQVAu6kET
        (hex!["fe55bea13108c5f9e070689c96d63c40ca79db709bebe921289003e56a1fdf27"].into(), 3 * CSPR),
        // sfJ4NLMc92S6gSvQLsxUvhh4zXwde1yHYJCBu2WFjwL1Hxgfh
        (hex!["c066d79465a7bd3138c770f52c1ad160272705e98f9b3dacc22bc70f010a1564"].into(), 12 * CSPR),
        // sfJcMpW8ESzTzpmftos8MoJ7pUyRbxPabxPHSuigfxQxy8GBR
        (hex!["d8ccf65eb5e93fdf7af47e9c6962a6822c7f0e8ed14d84f2bebdae0c5623e62b"].into(), 16 * CSPR),
        // sfESZE2fNkkRCR2bSmmKZ5VzmMGHFh8eUdE2isdjne7JGW9AU
        (hex!["2061f823e814d8c6b524da2f26ba2bfa048bbce57a1186e560b84c47a162b927"].into(), 1 * CSPR),
        // sfFSxdDQWSnuF2zJ3tRv3B9Xxzu8boEkByCSXkq1T1F6vRky5
        (hex!["4cecf92b37e6954f086002cf7b6a61ac7d9ba40c83ef963005e3cacfb5c1e13f"].into(), 21 * CSPR),
        // sfEivpTTfp6Xh7nHaco1sxXQiy163pT474cS2dj8d8MREaJ2x
        (hex!["2cde961358bf934533495f186755eb538a925aaa19ab4bad097f9d23665a9553"].into(), 24 * CSPR),
        // sfJHPU8JPeCg35QvgTwZ2iFAwiavxem4McAYtgvTKpePSnUrw
        (hex!["ca54d983c77c48c948fa9a6f9261ce2d9c4f20abf6632e28da3ec41d4752d519"].into(), 8 * CSPR),
        // sfDyruPst6vv93A1pUYtmNQa95iypWhMw1n4PWDfpP9g1WHTQ
        (hex!["0c05daf23268fdae4efd5bc1211f662c63399be10666ad3bdc75f3470a5b3378"].into(), 11 * CSPR),
        // sfG5dZrh8trJRWewe1THxhvCTdR1Qq6NDUkoGuQg4VA6iAm2z
        (hex!["68e4e6131e6a7aaf5ab2629d2ee721031df2e2a6573701862508fa3dc5765f5c"].into(), 4 * CSPR),
        // sfHNVjWNHs6fwPpHmmPj4nJQ7evN35qr9KkJVeiJjmyf3fGxj
        (hex!["a1fdef07d92813b10b15914afe763aa16bbf3feca8db73fabf1422cd48e05db0"].into(), 16 * CSPR),
        // sfEYCLQnQzp8EYfqqhWmB1mtWNPX9AmVLGiwhVpFVQ5JuuGmu
        (hex!["24af1eab02801a2d1afe16c75baa55f930138d58229f02f2840f387241529424"].into(), 18 * CSPR),
        // sfDwQQ2Zy16Hx5qnHQbsXw8reMewJ684yUydmTXT7E3Y489se
        (hex!["0a2622dc4be5606375d3a47e56e2580636b0057c46ec85bd44e149bff55fb943"].into(), 27 * CSPR),
        // sfFMhheEBKGwDcJ9aqpYvVsAAq3tu2tEcVaRd66zfxY8qaShs
        (hex!["48ea8240144388abb847a7b2c52f6290aeb77f1b6d8e10cda7d14a2f48b05035"].into(), 3 * CSPR),
        // sfE66BLe2b6wM9dWctMnizM7yzadJrzGtTDC64cMTmJxZqGG1
        (hex!["10c603d5a51516d1ee97212cf0b79f106332439750673b8605a527ffe1d45c50"].into(), 3 * CSPR),
        // sfEiXa1R4CGPDZcdJ7oEnTuwiicA5Dhtny8z7aYhSrbDQNygK
        (hex!["2c90529d502a1f3c51fcf487782b4defa09bd0e7470d1d080e44da713058241c"].into(), 24 * CSPR),
    ];

    // Following keys are used in genesis config for testing (casper) chains.
    // DO NOT use them in production chains such as ghost.
    let endowed_accounts = vec![
        // sfErNwRgZ6ypB7wY8M2smXMZjxqUkc2TgUcNvC1JNQJFXS8bw
        hex!["328d3b7c3046ef7700937d99fb2e98ce2591682c2b5dcf3f562e4da157650237"].into(),
        // sfEwRjyvEQcpRQ1qbCZum27nEkTggKEt7DtqxwyYQULt9UuUN
        hex!["3666e4e19f87bb8680495f31864ce1f1c69d4178002cc01911aef2cc7313f203"].into(),
        // sfHcJxw5cgkvukZZyxcNUMCdbm9e7773orByLrGgAREka81TK
        hex!["ac871e8bab00dd56ba3a1c0bd289357203dcaf10010b0b04ad7472870cd22a3c"].into(),
        // sfFD7KSRi2aSREJWc9X75sVTN4a5pbPM5VSSJefmPvMuiVbPr
        hex!["425ccd7bda4f5c76788ba23bc0381d7a2e496179c93301208c57501c80a4232a"].into(),
        // sfH29zyFYtoFj6fSXskAEXG5XyyMCa5YycahJkYMwSUz8CcEU
        hex!["927a98dcf8f721103005f168476c24b91d7d10d580f457006a908e10e62c7729"].into(),
        // sfHcRoUmrL8GDmWxUcPcZEWVfJbnaXyjWuaBxu5pNtdW5nERK
        hex!["ac9e227e30a63ce6eeb55cfbb1fb832aa7e1d3fad2bcb3f663de4a91d744fd50"].into(),
        // sfFJuDxqSc3skWaNUQgqmtCDYvcRj9c56urEky7ByD26aXQEW
        hex!["46c78fcacffd80abc9cca4917ef8369a37e21a1691ca11e7a3b53f80be745313"].into(),
        // sfKNNbANdBuBpA4n1sXwPBhV57HBgV2y3R3YjHz1S1uWKfKAy
        hex!["fa5e5a295ec74c3dda81118d9240db1552b28f831838465ae0712e97e78a6728"].into(),
        // sfFAdZQQVdbCTA7eWomTrJXe5L8ZcwZRfkyyRkMQZftDqbcMg
        hex!["4078ddb1ba1388f768fe6aa40ba9124a72692ecbcc83dc088fa86c735e4dc128"].into(),
        // sfFqT8fmF15Ddshio5rnucmqzMxtUoHZVh7qSALSdAaM7Y6zb
        hex!["5e1456904c40192cd3a18183df7dffea90d97739830a902cabb702ecdae4f649"].into(),
        // sfFzUcPxuourb6JtdiudRkrsbnkxne1KEcpksVMJYGau5BVTG
        hex!["64f685baa838323c0ef8c45259a3036b3e2bc54edf6553ce323e25b5e37a3721"].into(),
        // sfHLkJNKVyAsVMC4bQQwsm1EMyWgKLQH8FFnZzLC78dYJDqSp
        hex!["a0a87a75dba18037aa2e7b8036ce951e8d8356104758e15c9f44e2fd7d1bbc41"].into(),
        // sfGCg772bqKp3wH23EQbgSbCQ5Q8BCwmCJ39XjR3xLwq6foYD
        hex!["6e4429a8fa85cfe2a60488af446d57e719207831b2579b937325645e110bb666"].into(),
    ];

    let initial_authorities: Vec<(
        AccountId,
        AccountId,
        BabeId,
        GrandpaId,
        AuthorityDiscoveryId,
        SlowClapId,
    )> = vec![
        (
            // sfFXZmnDVnkQ781J2gbqUpi7K5KgMWMdM4eeii74xxGgKYnNN
            hex!["507045c82be367f95408466cd054ca39bfa52697a3ef22809af14cf9de304f02"].into(),
            // sfFXZmnDVnkQ781J2gbqUpi7K5KgMWMdM4eeii74xxGgKYnNN
            hex!["507045c82be367f95408466cd054ca39bfa52697a3ef22809af14cf9de304f02"].into(),
            // sfJeojACBa7WiH6tBwikBKAMU2oKmseEBD1GYUYATvfWuLcPa
            hex!["daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f"].unchecked_into(),
            // sfFdtzNxJdeEkgHxvk144rJKxf7wcYvgX5tqfgZRutW9YvAKE
            hex!["55446f9a7aa99ced06b317c80ce90d56b84e56526775683af2525969e8da0b64"].unchecked_into(),
            // sfE8gsMYAjAJHk5gyYZN7AW6pfmJ7V9H7xxWto24nmhzCUXaQ
            hex!["12c14850562021eb99f58f90ab624fb6cfaf3ac9228a92f8b60115fe6a6af15a"].unchecked_into(),
            // sfE3GKSrKZzrZpdapJ2VGRpPor45T4D4i8QBZNumSNGqGv7PX
            hex!["0e9e698c7b2bf5ce3861cb4bc4ddf9e200237c282025b093ada850d764d12a35"].unchecked_into(),
        ),
        (
            // sfHLqWNC4hMKHhwvPWmWcxZsDPhCTQKgh1Ap7pm3qML5GBTBa
            hex!["a0ba0196e6ee7e6b5b0553035c5cb5c04e9725001b5732839d0529cbc00c9600"].into(),
            // sfHLqWNC4hMKHhwvPWmWcxZsDPhCTQKgh1Ap7pm3qML5GBTBa
            hex!["a0ba0196e6ee7e6b5b0553035c5cb5c04e9725001b5732839d0529cbc00c9600"].into(),
            // sfGA6tPPF8dAc8QpMCMjxitG3j8sXPhkdpm5bwz4UsXAApUiw
            hex!["6c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e49"].unchecked_into(),
            // sfGxQZXFUQH1AXv82rpjiJHFs7YsdEuVGdyvKiS2Tajpvw6Se
            hex!["8f9ea20bf4a807a8e710f7559dece86e94672b5b361de157bdaa5c1f37849f8d"].unchecked_into(),
            // sfGz2enFUR22cQ5ey61MdtPqbCeEWZA1wsCFFSLGaK7vKnv8C
            hex!["90db5ed339a559ed157995a48d781f44c7df972dfba4bc855e4b59fa46438e17"].unchecked_into(),
            // sfEtwe5BoroNjkdLsvnjnMemUKiw8MS1X4YW8bepbbGvhS4LZ
            hex!["3481cdcbcf37a4669c29a78cf9ceb39383a10ef0a18b36b92d149fdd0c24ae00"].unchecked_into(),
        ),
        (
            // sfGq75CrCrkcfqNzyyidu3D4jW3AoJSzL5tKKuv1UbS16ezzy
            hex!["8a0d0b66e827bf20e79f9a499317e73925ce4f422371067edfab690e43857f13"].into(),
            // sfGq75CrCrkcfqNzyyidu3D4jW3AoJSzL5tKKuv1UbS16ezzy
            hex!["8a0d0b66e827bf20e79f9a499317e73925ce4f422371067edfab690e43857f13"].into(),
            // sfJo2ogBpssRAU9ZPTvuXFZEdmJw9pKsPydLjXe8DypRScjzT
            hex!["e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d42132475"].unchecked_into(),
            // sfHq3EVT1sqY7o5ki3zA6LEdRDfdFc29YaZN3w2Thhz6JD5ZF
            hex!["b63c5a0cf342b9b04931bc8ed74d7d0165ab99ab5f8a4514797d4b299a4501fe"].unchecked_into(),
            // sfEj3wrDy9EDLCAodyEdQEYxJpNnM8Etaj3RJ5bCBRzdaDced
            hex!["2cf69452e9f2a8457119139408884941ed50f590c0fc0f2b044c4d82c69e4245"].unchecked_into(),
            // sfE32RmBp1xX4KRTphVGLUJBxLGPN3Dzg9BwCJktxMf3iEwck
            hex!["0e6fa6934f9e99fa84874f2ed9318825a0d5443a0ced984acfbd24ece72ba55e"].unchecked_into(),
        ),
        (
            // sfG9iWUS7AKBzvqdz3uDZv7f1t79vvSTYL1VxzYPHjhmLnQVn
            hex!["6c0283f4c688f0e75ad546c790bbd5961c1a6931543aa589f368f8272c44b758"].into(),
            // sfG9iWUS7AKBzvqdz3uDZv7f1t79vvSTYL1VxzYPHjhmLnQVn
            hex!["6c0283f4c688f0e75ad546c790bbd5961c1a6931543aa589f368f8272c44b758"].into(),
            // sfGMUYXSjHgwGBpbGiHFoqT1DdJwZdHk49H5ViaQM7HUnayvZ
            hex!["74fa7381a7a74b316afb6793a00387eed9d95d46a69866cbb316b5d9c918af0e"].unchecked_into(),
            // sfEWYhczV6PbmeNXZTcA4LvhpzvCfNMatYoSNKvDphmNaQzqB
            hex!["236d2fa03f4ed8cb65de7e514d7540159b328f1c170dd402b094ad7fbf547218"].unchecked_into(),
            // sfDirg32ityDvrjxh4822unhP4qm4S9yTqN99gesN322swn7h
            hex!["00946618c353e4c6546b87f9ca1089b846b0ea4658ee8e6d9d1200c24cb5ee27"].unchecked_into(),
            // sfFZgp1Z5diFAZ16swuQD5GojGCsMMFVR19uWnCrppMLuYjRv
            hex!["520e74f8c5853ec8577932327ad3247656db25b74c79ad09adb431b271002401"].unchecked_into(),
        ),
        (
            // sfHjtrXFzRmxwjE4rjVxFJXpvVv7furjdymZS7PQRFiANpodz
            hex!["b24feb55b2cac4b365a9245c2a97525b01bd1a594d2d42b91f6bc38c9c2e6517"].into(),
            // sfHjtrXFzRmxwjE4rjVxFJXpvVv7furjdymZS7PQRFiANpodz
            hex!["b24feb55b2cac4b365a9245c2a97525b01bd1a594d2d42b91f6bc38c9c2e6517"].into(),
            // sfF5XWwvNPjZEsBz1HWs5Ys5zcE85UHnN1BV8TBBectqFQZRm
            hex!["3c944c704cae203619b9e7a5a4b6742736da6a8e76c762291bebdc7652cfec2f"].unchecked_into(),
            // sfDx3gj4wFHg3cK6bopnypHQ6TxW1VgyPsYVbXKhRHtLDLxQb
            hex!["0aa3a88f6b777c95c3dfe7e997b76798413f16aa325f34824cae0c9102b281d5"].unchecked_into(),
            // sfHXZbnZV3YWwnH28q2xumm7stvuC8LweYYxPNuHGonnX7QHL
            hex!["a8e828d10cf7b74481b6e746e5532d4740ea8014a0d3d856540a59847f8a6b76"].unchecked_into(),
            // sfEaHBrBgeMhRTA3WHE9Nbyvn3h7xkhYKi7go4yo81L88o9zJ
            hex!["2645f1f6820dd3a917eebbdab033088d8862477c1c14759b218685f9a0893377"].unchecked_into(),
        ),
        (
            // sfFFYKBEwmJAQEJR73Q4Gfs1sH1c8wyuBGnHc1UdzWucAYrKC
            hex!["44376f8fa786be1f16fcb45232cfb07300cea845b2fc6e30dde61952de3e5e33"].into(),
            // sfFFYKBEwmJAQEJR73Q4Gfs1sH1c8wyuBGnHc1UdzWucAYrKC
            hex!["44376f8fa786be1f16fcb45232cfb07300cea845b2fc6e30dde61952de3e5e33"].into(),
            // sfK4K5bS7M6bHeKHoGec9bw1PMngNyzhTx9YZq6hkqibos4LJ
            hex!["ec981eb1ef1ddbc8ded2db16198cb03667b4b39a8ea58f28ad469ddfaf256161"].unchecked_into(),
            // sfECakKMW2xf5dK8Ut55tnwadoKTNGKdRLh5E7dYRmV6sW812
            hex!["15b9a867891cf449584b108e512d60b945b1a065bec1703c4c5709ee5093c03d"].unchecked_into(),
            // sfErEin4Ljy11VGnYtTYJZ9LLcDP4fvsKV6f9LXYRwRXtrNqa
            hex!["3271915dc67eba8ad2759a30c2537702f4fbf45647cba565e3a464ab75b91f05"].unchecked_into(),
            // sfGD5sHSa1h8NGpUD29ZogBJW6fatg8Sg6Pzg9Q7RPUm24Mkr
            hex!["6e9426dc78fba9eeb264dcab98be86daf3d8cf510ecfb2acddec370295ff8176"].unchecked_into(),
        ),
        (
            // sfFPZZNrhDuY9MKJCBHyBCkgJecgDqPJBPSjA37be4czdX6t3
            hex!["4a5596e97c602e7846d54fae81dcdc5a553b7422231e32f9567ac30a6b7c743a"].into(),
            // sfFPZZNrhDuY9MKJCBHyBCkgJecgDqPJBPSjA37be4czdX6t3
            hex!["4a5596e97c602e7846d54fae81dcdc5a553b7422231e32f9567ac30a6b7c743a"].into(),
            // sfJP8aW6eSUs14AfUG6ZDFFjtyJxDed5Ubk1CFh7dNmL69rbx
            hex!["ceb63298b1b7a1277fddf6eee735dbbf9921fd5ebaac0132eee1963e22cf5935"].unchecked_into(),
            // sfH6jAeHqDpwtYGv9KJWNJ8aom8ivSvVztRSwAHw4bXd1isoP
            hex!["95f73a6271b517f2016fa91411bdeeb990158066c95f106a79697446ba9f78b4"].unchecked_into(),
            // sfEXSdKyx6uQBzgR3a7oH53XSCLrjUM2B7fbcvUvm21b5J6Uf
            hex!["241bfc05caa2d3e53e671df7261599c13f069a37f6cc4be10b5d49502c3a1e1c"].unchecked_into(),
            // sfGXqJTwJTkh3bwhECju7XCdgvJXYJZUtYSEJ2PbfpXGak42s
            hex!["7ce0c80ee65fb00e229d8c8fa5484144eca3d45d733165fbffcdb4de24c14951"].unchecked_into(),
        ),
        (
            // sfESE7VifnknxVe71z3zsqC3xiirXyzHurKjdQoD537WpwJjW
            hex!["2021a16182e3af39a79d20021a1b8755d589c04292d361d6b387411f7e975602"].into(),
            // sfESE7VifnknxVe71z3zsqC3xiirXyzHurKjdQoD537WpwJjW
            hex!["2021a16182e3af39a79d20021a1b8755d589c04292d361d6b387411f7e975602"].into(),
            // sfFzQmYYckD8XLV7XGU1pJAyt1K3foCpPumpKBqdb5sJGHXrc
            hex!["64e9968f3af2e1a86ee8d4be9ad77a1d66f50138527988bf93ede25baaf2e671"].unchecked_into(),
            // sfFHjCLzWetvQJQzNwxeWcrkHmnPS1mVz7gT63yiRdvxFZ9T8
            hex!["45e28f333bf0d4a9956ae20341cd07db8d471c4b482ed15d5cf7edd70201670d"].unchecked_into(),
            // sfHJAk4HiVuMjXqaXoFEKTCF6938Lta7qd9w3zbyyuWCs1T5L
            hex!["9eb1063afcaf568e7a62458ef33237a41ca500c89e084f7a5dd75bf5d89b105a"].unchecked_into(),
            // sfEm2SME5H6GiezhYokZWmrZLMTUNFbLV7xwgKrMXz3NwppKb
            hex!["2e77fde21162d1f21ca371846d70c3b75931329074101ee668e614336d25c120"].unchecked_into(),
        ),
        (
            // sfHpvEbP79MrDMVw4GhTvgLSU987ZSJ21VAsDWiJdgjG3ijse
            hex!["b624cb291f7464773f3b449ee2252165f3934ace08b1e10611a53e174766fc73"].into(),
            // sfHpvEbP79MrDMVw4GhTvgLSU987ZSJ21VAsDWiJdgjG3ijse
            hex!["b624cb291f7464773f3b449ee2252165f3934ace08b1e10611a53e174766fc73"].into(),
            // sfJHYLgjoHotvKi46URmtaVoG4p54SPE2ASTrauym99WxFcAn
            hex!["ca72b6ea2c83f9e429479bf51c324ea90cbf01e08d2850ced2590c8796cfe222"].unchecked_into(),
            // sfFVPqgCsDQe3k4qhGmUH4UoZaxsGb9majPgoH3WaYCZjFhTf
            hex!["4ec8584ca9da16d8c60e1770e98fbca8bec648e13c69601e3dfdc1330bf1f999"].unchecked_into(),
            // sfJ6nxM1SvcdbV2Gmf8WKkPKeX6rRYaEmSj7V9r64799acqHV
            hex!["c2403683be24a92ae8489e28fb502e2bab16d815c4f6c865c50ffb34430a8d7c"].unchecked_into(),
            // sfK1sQY3GL8waX2htW9EaBo9MjWGuy4VGeiUfP4NCq5tCjt37
            hex!["eabb3463e300f357b9886683d5a240a395f6bd41182057f03b0e9697a8b3465e"].unchecked_into(),
        ),
        (
            // sfJeU4TBQyuGxfsCqNDPax1TcfAseEmBDPqx5YEm7kXUvnnPa
            hex!["da6875e9df9a7894e065ef5befcde567dec4dc2c0b73a6ad5514dcca26a90702"].into(),
            // sfJeU4TBQyuGxfsCqNDPax1TcfAseEmBDPqx5YEm7kXUvnnPa
            hex!["da6875e9df9a7894e065ef5befcde567dec4dc2c0b73a6ad5514dcca26a90702"].into(),
            // sfGbxmQAD2jbktjRkq6NsJxHKHWnkdtvoR14fFPAX85t148ej
            hex!["8006e3f6e3d92c4c5f2e2f001452e4993e6d5c2b1136f2ae6060c6e9c9523b4a"].unchecked_into(),
            // sfGm1jJagueW5dCng6xKCDx3FX2JohtsYMuNjf2tJGXN5ePUL
            hex!["86ee138c9e7e67c1c2e157c0ba888761a122d8b9aa6a8653e886ac329e34255d"].unchecked_into(),
            // sfEB68auUQmSCK8M3Zr7WuzRSipj9sQ5ykfDmvLmT8FDY5bg6
            hex!["1496150847d512e0491899eba72ee36f76b882ae29fccf18201fd9fbd5bfd300"].unchecked_into(),
            // sfHZqUptNXpRNGPHKn2Tfv8K1RjFGJ9XCdSw41nPAw9ZXM37T
            hex!["aaa41b6ade4c30b5792aa6e5604c444e424900ddf649b23eed4bd0d7f5d3a34f"].unchecked_into(),
        ),
        (
            // sfFBEdrB1J7jLJKQp3fABEiHkwec1gCgGeTxMVyVm4UjWwvRs
            hex!["40eef1c6c8d8242ccbd3f03144bd4ea1a7374cbd8219e2849d3a3ee78f1da045"].into(),
            // sfFBEdrB1J7jLJKQp3fABEiHkwec1gCgGeTxMVyVm4UjWwvRs
            hex!["40eef1c6c8d8242ccbd3f03144bd4ea1a7374cbd8219e2849d3a3ee78f1da045"].into(),
            // sfF2FRJSuQSCidfbpu8DwpsHwezCcBJcZfh7Pds5vqtEF3Rbw
            hex!["3a145fb664353e473f1937058c881b14ed150285f3cec1aff348c5209d56d96d"].unchecked_into(),
            // sfDysi9h3PJoA5BGeJ2vfAkx3wXS9oK7yTDUyuJG2CRMJvXnh
            hex!["0c0891a518270014530061bd217606269686abdf3c1d237a3c6a3db308fc2d0d"].unchecked_into(),
            // sfGsyqzBAT7a9oBGdDBykyRwF95wRBL4yaGs4QFWznXHw5xsF
            hex!["8c3e730f6e6ecfb96581091e71556175384f077bee31b0199f13321df018427d"].unchecked_into(),
            // sfJP7W9aZe2F6G5w7xZtHhzSUCg86SvUcur4GPm2LMs7N2f5w
            hex!["ceb294227950d177b63e6c1d10a66131f5da3792428b03f5b83be84a33db215f"].unchecked_into(),
        ),
        (
            // sfFCsSaJrPqkCZMdkm7WoyHP7w3UbNaC3aCHQfWbUaLbDqfdR
            hex!["422e16b0c58f03af378d1638fe56127f337abf1d1a4a740c3371714616abd43d"].into(),
            // sfFCsSaJrPqkCZMdkm7WoyHP7w3UbNaC3aCHQfWbUaLbDqfdR
            hex!["422e16b0c58f03af378d1638fe56127f337abf1d1a4a740c3371714616abd43d"].into(),
            // sfGShS9zKf8nzDr71qPv9LZJtK1LCMxPV4QUMYG8jvZhVe9pS
            hex!["78f612068566eb6cc5cb5d9f1fda92c5dc3e3888eb61eb1af27af6855365ba3c"].unchecked_into(),
            // sfJg5cPBkyrcu7zZaKaUkjp2vDVGfpGNjjT1sn8fS6qjv9mDU
            hex!["dba3613933d60ca248ee024deac42bc9c8c2d9fe8734b6052cd9a148978cbedb"].unchecked_into(),
            // sfFav2ALRGkJtmEHEpz2LiRmshGPzn4aWdAZeFUyKA56LqDDF
            hex!["52fe2b63b03a0d439923967278442418a2d1f0d250bcab26f85f12ea212cbd3e"].unchecked_into(),
            // sfDmN4zoicQ54R5MmSpCf9ojg8zE2eD3x39pnba412oDivkBc
            hex!["027dd852bf20bef53545afd1e08bf8760abb6b1af1df6c17e73f4cf88210ee46"].unchecked_into(),
        ),
        (
            // sfF2fiFe2PteoYe286cZNJpxaT1omCPuTgwHjB1Z8tqjsLxRn
            hex!["3a6626211a2dd35683fd7cb5f2f343d75f2b698d6c48c2d6eb1cdbe116e32315"].into(),
            // sfF2fiFe2PteoYe286cZNJpxaT1omCPuTgwHjB1Z8tqjsLxRn
            hex!["3a6626211a2dd35683fd7cb5f2f343d75f2b698d6c48c2d6eb1cdbe116e32315"].into(),
            // sfG9m1LEV1sjUwyLwp1UQPUGnuMGF1oaCjSC4PVx9q4zgJRMr
            hex!["6c0aec49974aaff08ff962a2d8d7857227d027ed27a272cbc4acaa1ee937db0f"].unchecked_into(),
            // sfH3JwHTbimvG3SZLd5d8Ad8Ztvgb8NVSwxxzxYfArpXVYqFD
            hex!["935becdfb2e0d4fcd46ba82e680cfc447180de6b85ec42d17f1396a520b0c04f"].unchecked_into(),
            // sfGkKjBX5UdujuTrbxyepUzdU4Jew7DvgNs1UUM2HBLj4xNM5
            hex!["86676ad3cd2d970b86dee2f25d4318f9bba40455111f16300e114e7f00c58706"].unchecked_into(),
            // sfDisU5wryao4kcd4WuHyZZB6LfJrDuoQoU14cTiiJqD7Whoc
            hex!["009712519ba7dad1c682c871b94573ccaba8b7d530f7194fb16bf553fd7ae67d"].unchecked_into(),
        ),
    ];

    let ghost_accounts: Vec<(AccountId, u128, u8)> = casper_testnet_evm_accounts();
    let evm_networks = casper_testnet_evm_networks();

    const ENDOWMENT: u128 = 31 * CSPR;
    const STASH: u128 = 69 * CSPR;

    serde_json::json!({
        "balances": {
            "balances": endowed_accounts
                .iter()
                .map(|k: &AccountId| (k.clone(), ENDOWMENT))
                .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
                .chain(whales_endowments)
                .collect::<Vec<_>>(),
        },
        "session": {
            "keys": initial_authorities
                .iter()
                .map(|x| {
                    (
                        x.0.clone(),
                        x.0.clone(),
                        casper_session_keys(
                            x.2.clone(),
                            x.3.clone(),
                            x.4.clone(),
                            x.5.clone(),
                        ),
                    )
                })
                .collect::<Vec<_>>(),
        },
        "staking": {
            "validatorCount": 500,
            "minimumValidatorCount": 3,
            "stakers": initial_authorities
                .iter()
                .map(|x| {
                    (
                        x.0.clone(), 
                        x.0.clone(), 
                        STASH, 
                        casper::StakerStatus::<AccountId>::Validator,
                    )
                })
                .collect::<Vec<_>>(),
            "forceEra": Forcing::NotForcing,
            "slashRewardFraction": Perbill::from_percent(10),
            "minNominatorBond": 6_900 * STRH,
            "minValidatorBond": 6_900 * STRH,
        },
        "babe": {
            "epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG),
        },
        "ghostNetworks": {
            "networks": evm_networks,
        },
        "ghostClaims": {
            "total": ghost_accounts
                .iter()
                .fold(0, |acc, k| acc + k.1),
            "membersAndRanks": ghost_accounts
                .iter()
                .map(|k| (k.0.clone(), k.2.clone()))
                .collect::<Vec<_>>(),
        },
    })
}

#[cfg(feature = "casper-native")]
fn casper_development_config_genesis() -> serde_json::Value {
    testnet_config_genesis(
        vec![get_authority_keys_from_seed("Alice")],
        None, None, None,
    )
}

#[cfg(feature = "casper-native")]
fn casper_local_config_genesis() -> serde_json::Value {
    testnet_config_genesis(
        vec![
            get_authority_keys_from_seed("Alice"), 
            get_authority_keys_from_seed("Bob"),
        ],
        Some(casper_testnet_accounts()),
        Some(casper_testnet_evm_accounts()), 
        Some(casper_testnet_evm_networks()),
    )
}

#[cfg(feature = "casper-native")]
pub fn casper_development_config() -> Result<CasperChainSpec, String> {
    Ok(CasperChainSpec::builder(
        casper::WASM_BINARY.ok_or("Casper development wasm not available")?,
        Default::default(),
    )
    .with_name("Development")
    .with_id("casper_dev")
    .with_chain_type(ChainType::Development)
    .with_genesis_config_patch(casper_development_config_genesis())
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
    .with_properties(casper_chain_spec_properties())
    .build())
}

#[cfg(feature = "casper-native")]
pub fn casper_local_testnet_config() -> Result<CasperChainSpec, String> {
    Ok(CasperChainSpec::builder(
        casper::WASM_BINARY.ok_or("Casper local testnet wasm not available")?,
        Default::default(),
    )
    .with_name("Casper Local Testnet")
    .with_id("casper_local_testnet")
    .with_chain_type(ChainType::Local)
    .with_genesis_config_patch(casper_local_config_genesis())
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
    .with_properties(casper_chain_spec_properties())
    .build())
}

#[cfg(feature = "casper-native")]
pub fn casper_staging_testnet_config() -> Result<CasperChainSpec, String> {
    Ok(CasperChainSpec::builder(
        casper::WASM_BINARY.ok_or("Casper staging testnet wasm not available")?,
        Default::default(),
    )
    .with_name("Casper Staging Testnet")
    .with_id("casper_staging_testnet")
    .with_chain_type(ChainType::Live)
    .with_genesis_config_patch(casper_staging_config_genesis())
    .with_telemetry_endpoints(
        TelemetryEndpoints::new(vec![(CASPER_TELEMETRY_URL.to_string(), 0)])
            .expect("Casper Staging telemetry url is valid; qed"),
    )
    .with_protocol_id(DEFAULT_PROTOCOL_ID)
    .with_properties(casper_chain_spec_properties())
    .build())
}
