diff --git a/src/chain_spec.rs b/src/chain_spec.rs index 1d60e57..494e0cc 100644 --- a/src/chain_spec.rs +++ b/src/chain_spec.rs @@ -1,7 +1,7 @@ use std::path::Path; use eth2_network_config::Eth2NetworkConfig; -use types::{ChainSpec, Config, Hash256, MainnetEthSpec, MinimalEthSpec}; +use types::{ChainSpec, Config, GnosisEthSpec, Hash256, MainnetEthSpec, MinimalEthSpec}; use crate::{networks::SupportedNetworks, DepositError}; @@ -13,6 +13,12 @@ pub fn chain_spec_for_network(network: &SupportedNetworks) -> Result() .unwrap()) + } else if network_name.as_str() == "gnosis" { + Ok(Eth2NetworkConfig::constant(&network_name) + .unwrap() + .unwrap() + .chain_spec::() + .unwrap()) } else { Err(DepositError::InvalidNetworkName(format!( "unknown chain name: {network_name}" diff --git a/src/deposit.rs b/src/deposit.rs index 55f63f0..2b9bd81 100644 --- a/src/deposit.rs +++ b/src/deposit.rs @@ -296,6 +296,49 @@ mod test { ); } + #[test] + fn test_deposit_gnosis() { + let keystore = Keystore::from_json_str(KEYSTORE).unwrap(); + let keypair = keystore.decrypt_keypair(PASSWORD).unwrap(); + let key_material = VotingKeyMaterial { + keystore: Some(keystore.clone()), + keypair, + voting_secret: PlainText::from( + keystore + .decrypt_keypair(PASSWORD) + .unwrap() + .sk + .serialize() + .as_bytes() + .to_vec(), + ), + withdrawal_keypair: None, + }; + let withdrawal_creds = hex::decode(WITHDRAWAL_CREDENTIALS_ETH1).unwrap(); + let (deposit_data, _) = keystore_to_deposit( + &key_material, + &withdrawal_creds.as_slice(), + 32_000_000_000, + Some(crate::networks::SupportedNetworks::Gnosis), + None, + ) + .unwrap(); + + // Signature asserted here is generated with + // https://github.com/gnosischain/validator-data-generator + + // python ./staking_deposit/deposit.py existing-mnemonic --eth1_withdrawal_address=0x010000000000000000000000000000000000000001 + + // Please enter your mnemonic separated by spaces (" "): entire habit bottom mention spoil clown finger wheat motion fox axis mechanic country make garment bar blind stadium sugar water scissors canyon often ketchup + // Enter the index (key number) you wish to start generating more keys from. For example, if you've generated 4 keys in the past, you'd enter 4 here. [0]: 0 + // Please choose how many new validators you wish to run: 1 + // Please choose the (mainnet or testnet) network/chain name ['mainnet', 'ropsten', 'goerli', 'kiln', 'sepolia', 'gnosis', 'chiado']: [gnosis]: gnosis + assert_eq!( + "97cb6902975fc7cdcd685006ca972a22799aece787b9665af9e0b501e70a4db100cf280c99f1b20ea49c953b526b0e760b4a6d6a8d1092a6afbad3efdab8269384f2034c4fd97ebd8fc2101467b2fe6aeadcf5fcfaa11952be8d3939a55b10f7", + deposit_data.signature.to_string().as_str().strip_prefix("0x").unwrap() + ); + } + #[test] fn test_deposit_custom_testnet() { let keystore = Keystore::from_json_str(KEYSTORE).unwrap(); diff --git a/src/networks.rs b/src/networks.rs index 7925d37..50d99f2 100644 --- a/src/networks.rs +++ b/src/networks.rs @@ -7,6 +7,7 @@ use types::Hash256; pub enum SupportedNetworks { Mainnet, Holesky, + Gnosis, // These are legacy networks they are supported on best effort basis Prater, Goerli, @@ -19,6 +20,7 @@ impl std::fmt::Display for SupportedNetworks { SupportedNetworks::Holesky => "holesky", SupportedNetworks::Prater => "goerli", SupportedNetworks::Goerli => "goerli", + SupportedNetworks::Gnosis => "gnosis", }; write!(f, "{}", s) } @@ -41,6 +43,9 @@ lazy_static! { pub static ref GENESIS_VALIDATORS_ROOT_GOERLI: Hash256 = decode_genesis_validators_root( "043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb" ); + pub static ref GENESIS_VALIDATORS_ROOT_GNOSIS: Hash256 = decode_genesis_validators_root( + "f5dcb5564e829aab27264b9becd5dfaa017085611224cb3036f573368dbb9d47" + ); pub static ref GENESIS_VALIDATOR_ROOT: HashMap = HashMap::from([ ( SupportedNetworks::Mainnet, @@ -58,6 +63,10 @@ lazy_static! { SupportedNetworks::Holesky, GENESIS_VALIDATORS_ROOT_HOLESKY.to_owned() ), + ( + SupportedNetworks::Gnosis, + GENESIS_VALIDATORS_ROOT_GNOSIS.to_owned() + ) ]); } diff --git a/src/voluntary_exit/test.rs b/src/voluntary_exit/test.rs index c0bcb00..845b097 100644 --- a/src/voluntary_exit/test.rs +++ b/src/voluntary_exit/test.rs @@ -22,3 +22,24 @@ fn it_generates_presigned_exit_message() { assert_eq!(73682, signed_voluntary_exit.message.epoch.as_u64()); assert_eq!("0xa418543c8bdc266e00a45d7409386fffe02ad9ce3c1e707d562b38f7160966567602c518f6615edc8ecd964b978837f30a742c535dafc33137833b3aa6c30f4fecf37449de405ed50d8e436f21c6f58c0a48407037b1985507c3221ce53ba213", signed_voluntary_exit.signature.to_string()); } + +#[test] +fn it_generates_presigned_exit_message_gnosis() { + let (genesis_validators_root, spec) = + validators_root_and_spec(Some(SupportedNetworks::Gnosis), None); + + let (voluntary_exit, key_material) = + crate::voluntary_exit::voluntary_exit_message_from_mnemonic( + PHRASE.as_bytes(), + 0, + 100, + 73682, + ); + + let signed_voluntary_exit = + voluntary_exit.sign(&key_material.keypair.sk, genesis_validators_root, &spec); + + assert_eq!(100, signed_voluntary_exit.message.validator_index); + assert_eq!(73682, signed_voluntary_exit.message.epoch.as_u64()); + assert_eq!("0x8a237dd1b6127ebd9d7103e2117b8b093a049aa5a42f45c55bb17d3b689b9aa0fe5730954d9d322b6cf0eecc7205da03153cf7f155a46f582b704a511a5306267bbe6b78a71ef55a72709350770e05578253f54f7088514dcdf5f5c73db53c45", signed_voluntary_exit.signature.to_string()); +}