diff --git a/Cargo.lock b/Cargo.lock index a950b0c19..a128f88d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8393,6 +8393,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-std", "zeroize", ] diff --git a/coordinator/src/cosign_evaluator.rs b/coordinator/src/cosign_evaluator.rs index 29d9cc4b0..844360081 100644 --- a/coordinator/src/cosign_evaluator.rs +++ b/coordinator/src/cosign_evaluator.rs @@ -12,9 +12,9 @@ use tokio::{ use borsh::BorshSerialize; use sp_application_crypto::RuntimePublic; use serai_client::{ - primitives::{NETWORKS, NetworkId, Signature}, - validator_sets::primitives::{Session, ValidatorSet}, - SeraiError, TemporalSerai, Serai, + primitives::{ExternalNetworkId, Signature, EXTERNAL_NETWORKS}, + validator_sets::primitives::{ExternalValidatorSet, Session}, + Serai, SeraiError, TemporalSerai, }; use serai_db::{Get, DbTxn, Db, create_db}; @@ -28,17 +28,17 @@ use crate::{ create_db! { CosignDb { - ReceivedCosign: (set: ValidatorSet, block: [u8; 32]) -> CosignedBlock, - LatestCosign: (network: NetworkId) -> CosignedBlock, - DistinctChain: (set: ValidatorSet) -> (), + ReceivedCosign: (set: ExternalValidatorSet, block: [u8; 32]) -> CosignedBlock, + LatestCosign: (network: ExternalNetworkId) -> CosignedBlock, + DistinctChain: (set: ExternalValidatorSet) -> (), } } pub struct CosignEvaluator { db: Mutex, serai: Arc, - stakes: RwLock>>, - latest_cosigns: RwLock>, + stakes: RwLock>>, + latest_cosigns: RwLock>, } impl CosignEvaluator { @@ -79,7 +79,7 @@ impl CosignEvaluator { let serai = self.serai.as_of_latest_finalized_block().await?; let mut stakes = HashMap::new(); - for network in NETWORKS { + for network in EXTERNAL_NETWORKS { // Use if this network has published a Batch for a short-circuit of if they've ever set a key let set_key = serai.in_instructions().last_batch_for_network(network).await?.is_some(); if set_key { @@ -87,7 +87,7 @@ impl CosignEvaluator { network, serai .validator_sets() - .total_allocated_stake(network) + .total_allocated_stake(network.into()) .await? .expect("network which published a batch didn't have a stake set") .0, @@ -126,9 +126,9 @@ impl CosignEvaluator { async fn set_with_keys_fn( serai: &TemporalSerai<'_>, - network: NetworkId, - ) -> Result, SeraiError> { - let Some(latest_session) = serai.validator_sets().session(network).await? else { + network: ExternalNetworkId, + ) -> Result, SeraiError> { + let Some(latest_session) = serai.validator_sets().session(network.into()).await? else { log::warn!("received cosign from {:?}, which doesn't yet have a session", network); return Ok(None); }; @@ -136,13 +136,13 @@ impl CosignEvaluator { Ok(Some( if serai .validator_sets() - .keys(ValidatorSet { network, session: prior_session }) + .keys(ExternalValidatorSet { network, session: prior_session }) .await? .is_some() { - ValidatorSet { network, session: prior_session } + ExternalValidatorSet { network, session: prior_session } } else { - ValidatorSet { network, session: latest_session } + ExternalValidatorSet { network, session: latest_session } }, )) } @@ -204,16 +204,12 @@ impl CosignEvaluator { let mut total_stake = 0; let mut total_on_distinct_chain = 0; - for network in NETWORKS { - if network == NetworkId::Serai { - continue; - } - + for network in EXTERNAL_NETWORKS { // Get the current set for this network let set_with_keys = { let mut res; while { - res = set_with_keys_fn(&serai, cosign.network).await; + res = set_with_keys_fn(&serai, network).await; res.is_err() } { log::error!( @@ -231,7 +227,8 @@ impl CosignEvaluator { let stake = { let mut res; while { - res = serai.validator_sets().total_allocated_stake(set_with_keys.network).await; + res = + serai.validator_sets().total_allocated_stake(set_with_keys.network.into()).await; res.is_err() } { log::error!( @@ -271,7 +268,7 @@ impl CosignEvaluator { #[allow(clippy::new_ret_no_self)] pub fn new(db: D, p2p: P, serai: Arc) -> mpsc::UnboundedSender { let mut latest_cosigns = HashMap::new(); - for network in NETWORKS { + for network in EXTERNAL_NETWORKS { if let Some(cosign) = LatestCosign::get(&db, network) { latest_cosigns.insert(network, cosign); } diff --git a/coordinator/src/db.rs b/coordinator/src/db.rs index 04ee9d350..934e50506 100644 --- a/coordinator/src/db.rs +++ b/coordinator/src/db.rs @@ -6,9 +6,9 @@ use blake2::{ use scale::Encode; use borsh::{BorshSerialize, BorshDeserialize}; use serai_client::{ - primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet}, in_instructions::primitives::{Batch, SignedBatch}, + primitives::ExternalNetworkId, + validator_sets::primitives::{ExternalValidatorSet, Session}, }; pub use serai_db::*; @@ -18,21 +18,21 @@ use crate::tributary::{TributarySpec, Transaction, scanner::RecognizedIdType}; create_db!( MainDb { - HandledMessageDb: (network: NetworkId) -> u64, + HandledMessageDb: (network: ExternalNetworkId) -> u64, ActiveTributaryDb: () -> Vec, - RetiredTributaryDb: (set: ValidatorSet) -> (), + RetiredTributaryDb: (set: ExternalValidatorSet) -> (), FirstPreprocessDb: ( - network: NetworkId, + network: ExternalNetworkId, id_type: RecognizedIdType, id: &[u8] ) -> Vec>, - LastReceivedBatchDb: (network: NetworkId) -> u32, - ExpectedBatchDb: (network: NetworkId, id: u32) -> [u8; 32], - BatchDb: (network: NetworkId, id: u32) -> SignedBatch, - LastVerifiedBatchDb: (network: NetworkId) -> u32, - HandoverBatchDb: (set: ValidatorSet) -> u32, - LookupHandoverBatchDb: (network: NetworkId, batch: u32) -> Session, - QueuedBatchesDb: (set: ValidatorSet) -> Vec + LastReceivedBatchDb: (network: ExternalNetworkId) -> u32, + ExpectedBatchDb: (network: ExternalNetworkId, id: u32) -> [u8; 32], + BatchDb: (network: ExternalNetworkId, id: u32) -> SignedBatch, + LastVerifiedBatchDb: (network: ExternalNetworkId) -> u32, + HandoverBatchDb: (set: ExternalValidatorSet) -> u32, + LookupHandoverBatchDb: (network: ExternalNetworkId, batch: u32) -> Session, + QueuedBatchesDb: (set: ExternalValidatorSet) -> Vec } ); @@ -61,7 +61,7 @@ impl ActiveTributaryDb { ActiveTributaryDb::set(txn, &existing_bytes); } - pub fn retire_tributary(txn: &mut impl DbTxn, set: ValidatorSet) { + pub fn retire_tributary(txn: &mut impl DbTxn, set: ExternalValidatorSet) { let mut active = Self::active_tributaries(txn).1; for i in 0 .. active.len() { if active[i].set() == set { @@ -82,7 +82,7 @@ impl ActiveTributaryDb { impl FirstPreprocessDb { pub fn save_first_preprocess( txn: &mut impl DbTxn, - network: NetworkId, + network: ExternalNetworkId, id_type: RecognizedIdType, id: &[u8], preprocess: &Vec>, @@ -108,19 +108,19 @@ impl ExpectedBatchDb { } impl HandoverBatchDb { - pub fn set_handover_batch(txn: &mut impl DbTxn, set: ValidatorSet, batch: u32) { + pub fn set_handover_batch(txn: &mut impl DbTxn, set: ExternalValidatorSet, batch: u32) { Self::set(txn, set, &batch); LookupHandoverBatchDb::set(txn, set.network, batch, &set.session); } } impl QueuedBatchesDb { - pub fn queue(txn: &mut impl DbTxn, set: ValidatorSet, batch: &Transaction) { + pub fn queue(txn: &mut impl DbTxn, set: ExternalValidatorSet, batch: &Transaction) { let mut batches = Self::get(txn, set).unwrap_or_default(); batch.write(&mut batches).unwrap(); Self::set(txn, set, &batches); } - pub fn take(txn: &mut impl DbTxn, set: ValidatorSet) -> Vec { + pub fn take(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Vec { let batches_vec = Self::get(txn, set).unwrap_or_default(); txn.del(Self::key(set)); diff --git a/coordinator/src/main.rs b/coordinator/src/main.rs index 58de348d2..adcc49ef1 100644 --- a/coordinator/src/main.rs +++ b/coordinator/src/main.rs @@ -23,8 +23,8 @@ use serai_db::{DbTxn, Db}; use scale::Encode; use borsh::BorshSerialize; use serai_client::{ - primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet, KeyPair}, + primitives::ExternalNetworkId, + validator_sets::primitives::{ExternalValidatorSet, KeyPair, Session}, Public, Serai, SeraiInInstructions, }; @@ -79,7 +79,7 @@ pub struct ActiveTributary { #[derive(Clone)] pub enum TributaryEvent { NewTributary(ActiveTributary), - TributaryRetired(ValidatorSet), + TributaryRetired(ExternalValidatorSet), } // Creates a new tributary and sends it to all listeners. @@ -145,7 +145,7 @@ async fn handle_processor_message( p2p: &P, cosign_channel: &mpsc::UnboundedSender, tributaries: &HashMap>, - network: NetworkId, + network: ExternalNetworkId, msg: &processors::Message, ) -> bool { #[allow(clippy::nonminimal_bool)] @@ -193,7 +193,8 @@ async fn handle_processor_message( .iter() .map(|plan| plan.session) .filter(|session| { - RetiredTributaryDb::get(&txn, ValidatorSet { network, session: *session }).is_none() + RetiredTributaryDb::get(&txn, ExternalValidatorSet { network, session: *session }) + .is_none() }) .collect::>(); @@ -265,7 +266,7 @@ async fn handle_processor_message( } // This causes an action on Substrate yet not on any Tributary coordinator::ProcessorMessage::SignedSlashReport { session, signature } => { - let set = ValidatorSet { network, session: *session }; + let set = ExternalValidatorSet { network, session: *session }; let signature: &[u8] = signature.as_ref(); let signature = serai_client::Signature(signature.try_into().unwrap()); @@ -393,7 +394,7 @@ async fn handle_processor_message( if let Some(relevant_tributary_value) = relevant_tributary { if RetiredTributaryDb::get( &txn, - ValidatorSet { network: msg.network, session: relevant_tributary_value }, + ExternalValidatorSet { network: msg.network, session: relevant_tributary_value }, ) .is_some() { @@ -782,7 +783,7 @@ async fn handle_processor_messages( processors: Pro, p2p: P, cosign_channel: mpsc::UnboundedSender, - network: NetworkId, + network: ExternalNetworkId, mut tributary_event: mpsc::UnboundedReceiver>, ) { let mut tributaries = HashMap::new(); @@ -831,7 +832,7 @@ async fn handle_processor_messages( #[allow(clippy::too_many_arguments)] async fn handle_cosigns_and_batch_publication( mut db: D, - network: NetworkId, + network: ExternalNetworkId, mut tributary_event: mpsc::UnboundedReceiver>, ) { let mut tributaries = HashMap::new(); @@ -905,7 +906,7 @@ async fn handle_cosigns_and_batch_publication( for batch in start_id ..= last_id { let is_pre_handover = LookupHandoverBatchDb::get(&txn, network, batch + 1); if let Some(session) = is_pre_handover { - let set = ValidatorSet { network, session }; + let set = ExternalValidatorSet { network, session }; let mut queued = QueuedBatchesDb::take(&mut txn, set); // is_handover_batch is only set for handover `Batch`s we're participating in, making // this safe @@ -923,7 +924,8 @@ async fn handle_cosigns_and_batch_publication( let is_handover = LookupHandoverBatchDb::get(&txn, network, batch); if let Some(session) = is_handover { - for queued in QueuedBatchesDb::take(&mut txn, ValidatorSet { network, session }) { + for queued in QueuedBatchesDb::take(&mut txn, ExternalValidatorSet { network, session }) + { to_publish.push((session, queued)); } } @@ -970,10 +972,7 @@ pub async fn handle_processors( mut tributary_event: broadcast::Receiver>, ) { let mut channels = HashMap::new(); - for network in serai_client::primitives::NETWORKS { - if network == NetworkId::Serai { - continue; - } + for network in serai_client::primitives::EXTERNAL_NETWORKS { let (processor_send, processor_recv) = mpsc::unbounded_channel(); tokio::spawn(handle_processor_messages( db.clone(), @@ -1195,7 +1194,7 @@ pub async fn run( } }); - move |set: ValidatorSet, genesis, id_type, id: Vec| { + move |set: ExternalValidatorSet, genesis, id_type, id: Vec| { log::debug!("recognized ID {:?} {}", id_type, hex::encode(&id)); let mut raw_db = raw_db.clone(); let key = key.clone(); diff --git a/coordinator/src/p2p.rs b/coordinator/src/p2p.rs index cecb35176..a9fd288e3 100644 --- a/coordinator/src/p2p.rs +++ b/coordinator/src/p2p.rs @@ -11,7 +11,9 @@ use rand_core::{RngCore, OsRng}; use scale::{Decode, Encode}; use borsh::{BorshSerialize, BorshDeserialize}; -use serai_client::{primitives::NetworkId, validator_sets::primitives::ValidatorSet, Serai}; +use serai_client::{ + primitives::ExternalNetworkId, validator_sets::primitives::ExternalValidatorSet, Serai, +}; use serai_db::Db; @@ -69,7 +71,7 @@ const BLOCKS_PER_BATCH: usize = BLOCKS_PER_MINUTE + 1; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)] pub struct CosignedBlock { - pub network: NetworkId, + pub network: ExternalNetworkId, pub block_number: u64, pub block: [u8; 32], pub signature: [u8; 64], @@ -208,8 +210,8 @@ pub struct HeartbeatBatch { pub trait P2p: Send + Sync + Clone + fmt::Debug + TributaryP2p { type Id: Send + Sync + Clone + Copy + fmt::Debug; - async fn subscribe(&self, set: ValidatorSet, genesis: [u8; 32]); - async fn unsubscribe(&self, set: ValidatorSet, genesis: [u8; 32]); + async fn subscribe(&self, set: ExternalValidatorSet, genesis: [u8; 32]); + async fn unsubscribe(&self, set: ExternalValidatorSet, genesis: [u8; 32]); async fn send_raw(&self, to: Self::Id, msg: Vec); async fn broadcast_raw(&self, kind: P2pMessageKind, msg: Vec); @@ -309,7 +311,7 @@ struct Behavior { #[allow(clippy::type_complexity)] #[derive(Clone)] pub struct LibP2p { - subscribe: Arc>>, + subscribe: Arc>>, send: Arc)>>>, broadcast: Arc)>>>, receive: Arc>>>, @@ -397,7 +399,7 @@ impl LibP2p { let (receive_send, receive_recv) = mpsc::unbounded_channel(); let (subscribe_send, mut subscribe_recv) = mpsc::unbounded_channel(); - fn topic_for_set(set: ValidatorSet) -> IdentTopic { + fn topic_for_set(set: ExternalValidatorSet) -> IdentTopic { IdentTopic::new(format!("{LIBP2P_TOPIC}-{}", hex::encode(set.encode()))) } @@ -407,7 +409,8 @@ impl LibP2p { // The addrs we're currently dialing, and the networks associated with them let dialing_peers = Arc::new(RwLock::new(HashMap::new())); // The peers we're currently connected to, and the networks associated with them - let connected_peers = Arc::new(RwLock::new(HashMap::>::new())); + let connected_peers = + Arc::new(RwLock::new(HashMap::>::new())); // Find and connect to peers let (connect_to_network_send, mut connect_to_network_recv) = @@ -420,7 +423,7 @@ impl LibP2p { let connect_to_network_send = connect_to_network_send.clone(); async move { loop { - let connect = |network: NetworkId, addr: Multiaddr| { + let connect = |network: ExternalNetworkId, addr: Multiaddr| { let dialing_peers = dialing_peers.clone(); let connected_peers = connected_peers.clone(); let to_dial_send = to_dial_send.clone(); @@ -507,7 +510,7 @@ impl LibP2p { connect_to_network_networks.insert(network); } for network in connect_to_network_networks { - if let Ok(mut nodes) = serai.p2p_validators(network).await { + if let Ok(mut nodes) = serai.p2p_validators(network.into()).await { // If there's an insufficient amount of nodes known, connect to all yet add it // back and break if nodes.len() < TARGET_PEERS { @@ -557,7 +560,7 @@ impl LibP2p { // Subscribe to any new topics set = subscribe_recv.recv() => { - let (subscribe, set, genesis): (_, ValidatorSet, [u8; 32]) = + let (subscribe, set, genesis): (_, ExternalValidatorSet, [u8; 32]) = set.expect("subscribe_recv closed. are we shutting down?"); let topic = topic_for_set(set); if subscribe { @@ -776,7 +779,7 @@ impl LibP2p { impl P2p for LibP2p { type Id = PeerId; - async fn subscribe(&self, set: ValidatorSet, genesis: [u8; 32]) { + async fn subscribe(&self, set: ExternalValidatorSet, genesis: [u8; 32]) { self .subscribe .lock() @@ -785,7 +788,7 @@ impl P2p for LibP2p { .expect("subscribe_send closed. are we shutting down?"); } - async fn unsubscribe(&self, set: ValidatorSet, genesis: [u8; 32]) { + async fn unsubscribe(&self, set: ExternalValidatorSet, genesis: [u8; 32]) { self .subscribe .lock() diff --git a/coordinator/src/processors.rs b/coordinator/src/processors.rs index 9157e2a6e..cfdbfa251 100644 --- a/coordinator/src/processors.rs +++ b/coordinator/src/processors.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use serai_client::primitives::NetworkId; +use serai_client::primitives::ExternalNetworkId; use processor_messages::{ProcessorMessage, CoordinatorMessage}; use message_queue::{Service, Metadata, client::MessageQueue}; @@ -8,27 +8,27 @@ use message_queue::{Service, Metadata, client::MessageQueue}; #[derive(Clone, PartialEq, Eq, Debug)] pub struct Message { pub id: u64, - pub network: NetworkId, + pub network: ExternalNetworkId, pub msg: ProcessorMessage, } #[async_trait::async_trait] pub trait Processors: 'static + Send + Sync + Clone { - async fn send(&self, network: NetworkId, msg: impl Send + Into); - async fn recv(&self, network: NetworkId) -> Message; + async fn send(&self, network: ExternalNetworkId, msg: impl Send + Into); + async fn recv(&self, network: ExternalNetworkId) -> Message; async fn ack(&self, msg: Message); } #[async_trait::async_trait] impl Processors for Arc { - async fn send(&self, network: NetworkId, msg: impl Send + Into) { + async fn send(&self, network: ExternalNetworkId, msg: impl Send + Into) { let msg: CoordinatorMessage = msg.into(); let metadata = Metadata { from: self.service, to: Service::Processor(network), intent: msg.intent() }; let msg = borsh::to_vec(&msg).unwrap(); self.queue(metadata, msg).await; } - async fn recv(&self, network: NetworkId) -> Message { + async fn recv(&self, network: ExternalNetworkId) -> Message { let msg = self.next(Service::Processor(network)).await; assert_eq!(msg.from, Service::Processor(network)); diff --git a/coordinator/src/substrate/cosign.rs b/coordinator/src/substrate/cosign.rs index 005607632..644ddf13a 100644 --- a/coordinator/src/substrate/cosign.rs +++ b/coordinator/src/substrate/cosign.rs @@ -19,9 +19,9 @@ use ciphersuite::{Ciphersuite, Ristretto}; use borsh::{BorshSerialize, BorshDeserialize}; use serai_client::{ - SeraiError, Serai, - primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet}, + primitives::ExternalNetworkId, + validator_sets::primitives::{ExternalValidatorSet, Session}, + Serai, SeraiError, }; use serai_db::*; @@ -70,13 +70,18 @@ impl LatestCosignedBlock { db_channel! { SubstrateDbChannels { - CosignTransactions: (network: NetworkId) -> (Session, u64, [u8; 32]), + CosignTransactions: (network: ExternalNetworkId) -> (Session, u64, [u8; 32]), } } impl CosignTransactions { // Append a cosign transaction. - pub fn append_cosign(txn: &mut impl DbTxn, set: ValidatorSet, number: u64, hash: [u8; 32]) { + pub fn append_cosign( + txn: &mut impl DbTxn, + set: ExternalValidatorSet, + number: u64, + hash: [u8; 32], + ) { CosignTransactions::send(txn, set.network, &(set.session, number, hash)) } } @@ -256,22 +261,22 @@ async fn advance_cosign_protocol_inner( // Using the keys of the prior block ensures this deadlock isn't reached let serai = serai.as_of(actual_block.header.parent_hash.into()); - for network in serai_client::primitives::NETWORKS { + for network in serai_client::primitives::EXTERNAL_NETWORKS { // Get the latest session to have set keys let set_with_keys = { - let Some(latest_session) = serai.validator_sets().session(network).await? else { + let Some(latest_session) = serai.validator_sets().session(network.into()).await? else { continue; }; let prior_session = Session(latest_session.0.saturating_sub(1)); if serai .validator_sets() - .keys(ValidatorSet { network, session: prior_session }) + .keys(ExternalValidatorSet { network, session: prior_session }) .await? .is_some() { - ValidatorSet { network, session: prior_session } + ExternalValidatorSet { network, session: prior_session } } else { - let set = ValidatorSet { network, session: latest_session }; + let set = ExternalValidatorSet { network, session: latest_session }; if serai.validator_sets().keys(set).await?.is_none() { continue; } @@ -280,7 +285,7 @@ async fn advance_cosign_protocol_inner( }; log::debug!("{:?} will be cosigning {block}", set_with_keys.network); - cosigning.push((set_with_keys, in_set(key, &serai, set_with_keys).await?.unwrap())); + cosigning.push((set_with_keys, in_set(key, &serai, set_with_keys.into()).await?.unwrap())); } break; diff --git a/coordinator/src/substrate/db.rs b/coordinator/src/substrate/db.rs index 2621e5ef7..524931057 100644 --- a/coordinator/src/substrate/db.rs +++ b/coordinator/src/substrate/db.rs @@ -1,4 +1,4 @@ -use serai_client::primitives::NetworkId; +use serai_client::primitives::ExternalNetworkId; pub use serai_db::*; @@ -9,7 +9,7 @@ mod inner_db { SubstrateDb { NextBlock: () -> u64, HandledEvent: (block: [u8; 32]) -> u32, - BatchInstructionsHashDb: (network: NetworkId, id: u32) -> [u8; 32] + BatchInstructionsHashDb: (network: ExternalNetworkId, id: u32) -> [u8; 32] } ); } diff --git a/coordinator/src/substrate/mod.rs b/coordinator/src/substrate/mod.rs index fb1e3aed2..a10806a39 100644 --- a/coordinator/src/substrate/mod.rs +++ b/coordinator/src/substrate/mod.rs @@ -9,11 +9,14 @@ use zeroize::Zeroizing; use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; use serai_client::{ - SeraiError, Block, Serai, TemporalSerai, - primitives::{BlockHash, NetworkId}, - validator_sets::{primitives::ValidatorSet, ValidatorSetsEvent}, - in_instructions::InInstructionsEvent, coins::CoinsEvent, + in_instructions::InInstructionsEvent, + primitives::{BlockHash, ExternalNetworkId}, + validator_sets::{ + primitives::{ExternalValidatorSet, ValidatorSet}, + ValidatorSetsEvent, + }, + Block, Serai, SeraiError, TemporalSerai, }; use serai_db::DbTxn; @@ -52,9 +55,9 @@ async fn handle_new_set( new_tributary_spec: &mpsc::UnboundedSender, serai: &Serai, block: &Block, - set: ValidatorSet, + set: ExternalValidatorSet, ) -> Result<(), SeraiError> { - if in_set(key, &serai.as_of(block.hash()), set) + if in_set(key, &serai.as_of(block.hash()), set.into()) .await? .expect("NewSet for set which doesn't exist") { @@ -64,7 +67,7 @@ async fn handle_new_set( let serai = serai.as_of(block.hash()); let serai = serai.validator_sets(); let set_participants = - serai.participants(set.network).await?.expect("NewSet for set which doesn't exist"); + serai.participants(set.network.into()).await?.expect("NewSet for set which doesn't exist"); set_participants.into_iter().map(|(k, w)| (k, u16::try_from(w).unwrap())).collect::>() }; @@ -131,7 +134,7 @@ async fn handle_batch_and_burns( }; let mut batch_block = HashMap::new(); - let mut batches = HashMap::>::new(); + let mut batches = HashMap::>::new(); let mut burns = HashMap::new(); let serai = serai.as_of(block.hash()); @@ -205,8 +208,8 @@ async fn handle_block( db: &mut D, key: &Zeroizing<::F>, new_tributary_spec: &mpsc::UnboundedSender, - perform_slash_report: &mpsc::UnboundedSender, - tributary_retired: &mpsc::UnboundedSender, + perform_slash_report: &mpsc::UnboundedSender, + tributary_retired: &mpsc::UnboundedSender, processors: &Pro, serai: &Serai, block: Block, @@ -226,12 +229,8 @@ async fn handle_block( panic!("NewSet event wasn't NewSet: {new_set:?}"); }; - // If this is Serai, do nothing // We only coordinate/process external networks - if set.network == NetworkId::Serai { - continue; - } - + let Ok(set) = ExternalValidatorSet::try_from(set) else { continue }; if HandledEvent::is_unhandled(db, hash, event_id) { log::info!("found fresh new set event {:?}", new_set); let mut txn = db.txn(); @@ -286,10 +285,7 @@ async fn handle_block( panic!("AcceptedHandover event wasn't AcceptedHandover: {accepted_handover:?}"); }; - if set.network == NetworkId::Serai { - continue; - } - + let Ok(set) = ExternalValidatorSet::try_from(set) else { continue }; if HandledEvent::is_unhandled(db, hash, event_id) { log::info!("found fresh accepted handover event {:?}", accepted_handover); // TODO: This isn't atomic with the event handling @@ -307,10 +303,7 @@ async fn handle_block( panic!("SetRetired event wasn't SetRetired: {retired_set:?}"); }; - if set.network == NetworkId::Serai { - continue; - } - + let Ok(set) = ExternalValidatorSet::try_from(set) else { continue }; if HandledEvent::is_unhandled(db, hash, event_id) { log::info!("found fresh set retired event {:?}", retired_set); let mut txn = db.txn(); @@ -340,8 +333,8 @@ async fn handle_new_blocks( db: &mut D, key: &Zeroizing<::F>, new_tributary_spec: &mpsc::UnboundedSender, - perform_slash_report: &mpsc::UnboundedSender, - tributary_retired: &mpsc::UnboundedSender, + perform_slash_report: &mpsc::UnboundedSender, + tributary_retired: &mpsc::UnboundedSender, processors: &Pro, serai: &Serai, next_block: &mut u64, @@ -395,8 +388,8 @@ pub async fn scan_task( processors: Pro, serai: Arc, new_tributary_spec: mpsc::UnboundedSender, - perform_slash_report: mpsc::UnboundedSender, - tributary_retired: mpsc::UnboundedSender, + perform_slash_report: mpsc::UnboundedSender, + tributary_retired: mpsc::UnboundedSender, ) { log::info!("scanning substrate"); let mut next_substrate_block = NextBlock::get(&db).unwrap_or_default(); @@ -494,9 +487,12 @@ pub async fn scan_task( /// retry. pub(crate) async fn expected_next_batch( serai: &Serai, - network: NetworkId, + network: ExternalNetworkId, ) -> Result { - async fn expected_next_batch_inner(serai: &Serai, network: NetworkId) -> Result { + async fn expected_next_batch_inner( + serai: &Serai, + network: ExternalNetworkId, + ) -> Result { let serai = serai.as_of_latest_finalized_block().await?; let last = serai.in_instructions().last_batch_for_network(network).await?; Ok(if let Some(last) = last { last + 1 } else { 0 }) @@ -519,7 +515,7 @@ pub(crate) async fn expected_next_batch( /// This is deemed fine. pub(crate) async fn verify_published_batches( txn: &mut D::Transaction<'_>, - network: NetworkId, + network: ExternalNetworkId, optimistic_up_to: u32, ) -> Option { // TODO: Localize from MainDb to SubstrateDb diff --git a/coordinator/src/tests/mod.rs b/coordinator/src/tests/mod.rs index db4c158fd..1d9d6d345 100644 --- a/coordinator/src/tests/mod.rs +++ b/coordinator/src/tests/mod.rs @@ -4,7 +4,7 @@ use std::{ collections::{VecDeque, HashSet, HashMap}, }; -use serai_client::{primitives::NetworkId, validator_sets::primitives::ValidatorSet}; +use serai_client::{primitives::ExternalNetworkId, validator_sets::primitives::ExternalValidatorSet}; use processor_messages::CoordinatorMessage; @@ -20,7 +20,7 @@ use crate::{ pub mod tributary; #[derive(Clone)] -pub struct MemProcessors(pub Arc>>>); +pub struct MemProcessors(pub Arc>>>); impl MemProcessors { #[allow(clippy::new_without_default)] pub fn new() -> MemProcessors { @@ -30,12 +30,12 @@ impl MemProcessors { #[async_trait::async_trait] impl Processors for MemProcessors { - async fn send(&self, network: NetworkId, msg: impl Send + Into) { + async fn send(&self, network: ExternalNetworkId, msg: impl Send + Into) { let mut processors = self.0.write().await; let processor = processors.entry(network).or_insert_with(VecDeque::new); processor.push_back(msg.into()); } - async fn recv(&self, _: NetworkId) -> Message { + async fn recv(&self, _: ExternalNetworkId) -> Message { todo!() } async fn ack(&self, _: Message) { @@ -65,8 +65,8 @@ impl LocalP2p { impl P2p for LocalP2p { type Id = usize; - async fn subscribe(&self, _set: ValidatorSet, _genesis: [u8; 32]) {} - async fn unsubscribe(&self, _set: ValidatorSet, _genesis: [u8; 32]) {} + async fn subscribe(&self, _set: ExternalValidatorSet, _genesis: [u8; 32]) {} + async fn unsubscribe(&self, _set: ExternalValidatorSet, _genesis: [u8; 32]) {} async fn send_raw(&self, to: Self::Id, msg: Vec) { let mut msg_ref = msg.as_slice(); diff --git a/coordinator/src/tests/tributary/chain.rs b/coordinator/src/tests/tributary/chain.rs index 7fc6a0647..62feb78bf 100644 --- a/coordinator/src/tests/tributary/chain.rs +++ b/coordinator/src/tests/tributary/chain.rs @@ -15,8 +15,8 @@ use ciphersuite::{ use sp_application_crypto::sr25519; use borsh::BorshDeserialize; use serai_client::{ - primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet}, + primitives::ExternalNetworkId, + validator_sets::primitives::{ExternalValidatorSet, Session}, }; use tokio::time::sleep; @@ -50,7 +50,7 @@ pub fn new_spec( let start_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); - let set = ValidatorSet { session: Session(0), network: NetworkId::Bitcoin }; + let set = ExternalValidatorSet { session: Session(0), network: ExternalNetworkId::Bitcoin }; let set_participants = keys .iter() diff --git a/coordinator/src/tests/tributary/dkg.rs b/coordinator/src/tests/tributary/dkg.rs index 04a528f90..adaa66431 100644 --- a/coordinator/src/tests/tributary/dkg.rs +++ b/coordinator/src/tests/tributary/dkg.rs @@ -10,7 +10,7 @@ use frost::Participant; use sp_runtime::traits::Verify; use serai_client::{ primitives::{SeraiAddress, Signature}, - validator_sets::primitives::{ValidatorSet, KeyPair}, + validator_sets::primitives::{ExternalValidatorSet, KeyPair}, }; use tokio::time::sleep; @@ -350,7 +350,7 @@ async fn dkg_test() { async fn publish_set_keys( &self, _db: &(impl Sync + Get), - set: ValidatorSet, + set: ExternalValidatorSet, removed: Vec, key_pair: KeyPair, signature: Signature, @@ -362,7 +362,7 @@ async fn dkg_test() { &*serai_client::validator_sets::primitives::set_keys_message(&set, &[], &key_pair), &serai_client::Public( frost::dkg::musig::musig_key::( - &serai_client::validator_sets::primitives::musig_context(set), + &serai_client::validator_sets::primitives::musig_context(set.into()), &self.spec.validators().into_iter().map(|(validator, _)| validator).collect::>() ) .unwrap() diff --git a/coordinator/src/tests/tributary/mod.rs b/coordinator/src/tests/tributary/mod.rs index c3f983116..1016248dd 100644 --- a/coordinator/src/tests/tributary/mod.rs +++ b/coordinator/src/tests/tributary/mod.rs @@ -7,7 +7,7 @@ use ciphersuite::{group::Group, Ciphersuite, Ristretto}; use scale::{Encode, Decode}; use serai_client::{ primitives::{SeraiAddress, Signature}, - validator_sets::primitives::{MAX_KEY_SHARES_PER_SET, ValidatorSet, KeyPair}, + validator_sets::primitives::{ExternalValidatorSet, KeyPair, MAX_KEY_SHARES_PER_SET}, }; use processor_messages::coordinator::SubstrateSignableId; @@ -31,7 +31,7 @@ impl PublishSeraiTransaction for () { async fn publish_set_keys( &self, _db: &(impl Sync + serai_db::Get), - _set: ValidatorSet, + _set: ExternalValidatorSet, _removed: Vec, _key_pair: KeyPair, _signature: Signature, diff --git a/coordinator/src/tributary/db.rs b/coordinator/src/tributary/db.rs index fda1c47ba..fe39b7de1 100644 --- a/coordinator/src/tributary/db.rs +++ b/coordinator/src/tributary/db.rs @@ -6,7 +6,7 @@ use borsh::{BorshSerialize, BorshDeserialize}; use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; use frost::Participant; -use serai_client::validator_sets::primitives::{KeyPair, ValidatorSet}; +use serai_client::validator_sets::primitives::{KeyPair, ExternalValidatorSet}; use processor_messages::coordinator::SubstrateSignableId; @@ -46,7 +46,7 @@ pub enum Accumulation { create_db!( Tributary { SeraiBlockNumber: (hash: [u8; 32]) -> u64, - SeraiDkgCompleted: (spec: ValidatorSet) -> [u8; 32], + SeraiDkgCompleted: (spec: ExternalValidatorSet) -> [u8; 32], TributaryBlockNumber: (block: [u8; 32]) -> u32, LastHandledBlock: (genesis: [u8; 32]) -> [u8; 32], @@ -80,7 +80,7 @@ create_db!( SlashReports: (genesis: [u8; 32], signer: [u8; 32]) -> Vec, SlashReported: (genesis: [u8; 32]) -> u16, SlashReportCutOff: (genesis: [u8; 32]) -> u64, - SlashReport: (set: ValidatorSet) -> Vec<([u8; 32], u32)>, + SlashReport: (set: ExternalValidatorSet) -> Vec<([u8; 32], u32)>, } ); diff --git a/coordinator/src/tributary/mod.rs b/coordinator/src/tributary/mod.rs index cc9bdb1ea..27bb6396b 100644 --- a/coordinator/src/tributary/mod.rs +++ b/coordinator/src/tributary/mod.rs @@ -1,6 +1,6 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; -use serai_client::validator_sets::primitives::ValidatorSet; +use serai_client::validator_sets::primitives::ExternalValidatorSet; use tributary::{ ReadWrite, @@ -40,7 +40,7 @@ pub fn removed_as_of_dkg_attempt( pub fn removed_as_of_set_keys( getter: &impl Get, - set: ValidatorSet, + set: ExternalValidatorSet, genesis: [u8; 32], ) -> Option::G>> { // SeraiDkgCompleted has the key placed on-chain. diff --git a/coordinator/src/tributary/scanner.rs b/coordinator/src/tributary/scanner.rs index 9b56e0a0f..8e1f48427 100644 --- a/coordinator/src/tributary/scanner.rs +++ b/coordinator/src/tributary/scanner.rs @@ -10,7 +10,7 @@ use tokio::sync::broadcast; use scale::{Encode, Decode}; use serai_client::{ primitives::{SeraiAddress, Signature}, - validator_sets::primitives::{KeyPair, ValidatorSet}, + validator_sets::primitives::{ExternalValidatorSet, KeyPair}, Serai, }; @@ -38,7 +38,7 @@ pub enum RecognizedIdType { pub trait RIDTrait { async fn recognized_id( &self, - set: ValidatorSet, + set: ExternalValidatorSet, genesis: [u8; 32], kind: RecognizedIdType, id: Vec, @@ -47,12 +47,12 @@ pub trait RIDTrait { #[async_trait::async_trait] impl< FRid: Send + Future, - F: Sync + Fn(ValidatorSet, [u8; 32], RecognizedIdType, Vec) -> FRid, + F: Sync + Fn(ExternalValidatorSet, [u8; 32], RecognizedIdType, Vec) -> FRid, > RIDTrait for F { async fn recognized_id( &self, - set: ValidatorSet, + set: ExternalValidatorSet, genesis: [u8; 32], kind: RecognizedIdType, id: Vec, @@ -66,7 +66,7 @@ pub trait PublishSeraiTransaction { async fn publish_set_keys( &self, db: &(impl Sync + Get), - set: ValidatorSet, + set: ExternalValidatorSet, removed: Vec, key_pair: KeyPair, signature: Signature, @@ -86,7 +86,7 @@ mod impl_pst_for_serai { async fn publish( serai: &Serai, db: &impl Get, - set: ValidatorSet, + set: ExternalValidatorSet, tx: serai_client::Transaction, meta: $Meta, ) -> bool { @@ -128,7 +128,7 @@ mod impl_pst_for_serai { async fn publish_set_keys( &self, db: &(impl Sync + Get), - set: ValidatorSet, + set: ExternalValidatorSet, removed: Vec, key_pair: KeyPair, signature: Signature, @@ -140,7 +140,7 @@ mod impl_pst_for_serai { key_pair, signature, ); - async fn check(serai: SeraiValidatorSets<'_>, set: ValidatorSet, (): ()) -> bool { + async fn check(serai: SeraiValidatorSets<'_>, set: ExternalValidatorSet, (): ()) -> bool { if matches!(serai.keys(set).await, Ok(Some(_))) { log::info!("another coordinator set key pair for {:?}", set); return true; diff --git a/coordinator/src/tributary/signing_protocol.rs b/coordinator/src/tributary/signing_protocol.rs index a90ed4799..20dda48eb 100644 --- a/coordinator/src/tributary/signing_protocol.rs +++ b/coordinator/src/tributary/signing_protocol.rs @@ -119,7 +119,7 @@ impl SigningProtocol<'_, T, C> { let algorithm = Schnorrkel::new(b"substrate"); let keys: ThresholdKeys = - musig(&musig_context(self.spec.set()), self.key, participants) + musig(&musig_context(self.spec.set().into()), self.key, participants) .expect("signing for a set we aren't in/validator present multiple times") .into(); diff --git a/coordinator/src/tributary/spec.rs b/coordinator/src/tributary/spec.rs index 92905490f..345584b6d 100644 --- a/coordinator/src/tributary/spec.rs +++ b/coordinator/src/tributary/spec.rs @@ -9,7 +9,7 @@ use frost::Participant; use scale::Encode; use borsh::{BorshSerialize, BorshDeserialize}; -use serai_client::{primitives::PublicKey, validator_sets::primitives::ValidatorSet}; +use serai_client::{primitives::PublicKey, validator_sets::primitives::ExternalValidatorSet}; fn borsh_serialize_validators( validators: &Vec<(::G, u16)>, @@ -43,7 +43,7 @@ fn borsh_deserialize_validators( pub struct TributarySpec { serai_block: [u8; 32], start_time: u64, - set: ValidatorSet, + set: ExternalValidatorSet, #[borsh( serialize_with = "borsh_serialize_validators", deserialize_with = "borsh_deserialize_validators" @@ -55,7 +55,7 @@ impl TributarySpec { pub fn new( serai_block: [u8; 32], start_time: u64, - set: ValidatorSet, + set: ExternalValidatorSet, set_participants: Vec<(PublicKey, u16)>, ) -> TributarySpec { let mut validators = vec![]; @@ -68,7 +68,7 @@ impl TributarySpec { Self { serai_block, start_time, set, validators } } - pub fn set(&self) -> ValidatorSet { + pub fn set(&self) -> ExternalValidatorSet { self.set } diff --git a/message-queue/src/main.rs b/message-queue/src/main.rs index c43cc3c84..b1c6e85ba 100644 --- a/message-queue/src/main.rs +++ b/message-queue/src/main.rs @@ -6,7 +6,7 @@ pub(crate) use std::{ pub(crate) use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; pub(crate) use schnorr_signatures::SchnorrSignature; -pub(crate) use serai_primitives::NetworkId; +pub(crate) use serai_primitives::ExternalNetworkId; pub(crate) use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, @@ -193,10 +193,7 @@ async fn main() { KEYS.write().unwrap().insert(service, key); let mut queues = QUEUES.write().unwrap(); if service == Service::Coordinator { - for network in serai_primitives::NETWORKS { - if network == NetworkId::Serai { - continue; - } + for network in serai_primitives::EXTERNAL_NETWORKS { queues.insert( (service, Service::Processor(network)), RwLock::new(Queue(db.clone(), service, Service::Processor(network))), @@ -210,17 +207,13 @@ async fn main() { } }; - // Make queues for each NetworkId, other than Serai - for network in serai_primitives::NETWORKS { - if network == NetworkId::Serai { - continue; - } + // Make queues for each ExternalNetworkId + for network in serai_primitives::EXTERNAL_NETWORKS { // Use a match so we error if the list of NetworkIds changes let Some(key) = read_key(match network { - NetworkId::Serai => unreachable!(), - NetworkId::Bitcoin => "BITCOIN_KEY", - NetworkId::Ethereum => "ETHEREUM_KEY", - NetworkId::Monero => "MONERO_KEY", + ExternalNetworkId::Bitcoin => "BITCOIN_KEY", + ExternalNetworkId::Ethereum => "ETHEREUM_KEY", + ExternalNetworkId::Monero => "MONERO_KEY", }) else { continue; }; diff --git a/message-queue/src/messages.rs b/message-queue/src/messages.rs index 942f3ff51..13c3dee0e 100644 --- a/message-queue/src/messages.rs +++ b/message-queue/src/messages.rs @@ -3,11 +3,11 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; use borsh::{BorshSerialize, BorshDeserialize}; -use serai_primitives::NetworkId; +use serai_primitives::ExternalNetworkId; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)] pub enum Service { - Processor(NetworkId), + Processor(ExternalNetworkId), Coordinator, } diff --git a/processor/src/batch_signer.rs b/processor/src/batch_signer.rs index 41f50322c..64cbb8a08 100644 --- a/processor/src/batch_signer.rs +++ b/processor/src/batch_signer.rs @@ -17,7 +17,7 @@ use frost_schnorrkel::Schnorrkel; use log::{info, debug, warn}; use serai_client::{ - primitives::{NetworkId, BlockHash}, + primitives::{ExternalNetworkId, BlockHash}, in_instructions::primitives::{Batch, SignedBatch, batch_message}, validator_sets::primitives::Session, }; @@ -41,7 +41,7 @@ type SignatureShare = as SignMachin pub struct BatchSigner { db: PhantomData, - network: NetworkId, + network: ExternalNetworkId, session: Session, keys: Vec>, @@ -65,7 +65,7 @@ impl fmt::Debug for BatchSigner { impl BatchSigner { pub fn new( - network: NetworkId, + network: ExternalNetworkId, session: Session, keys: Vec>, ) -> BatchSigner { diff --git a/processor/src/main.rs b/processor/src/main.rs index e0d97aa68..98b09a066 100644 --- a/processor/src/main.rs +++ b/processor/src/main.rs @@ -9,7 +9,7 @@ use log::{info, warn}; use tokio::time::sleep; use serai_client::{ - primitives::{BlockHash, NetworkId}, + primitives::{BlockHash, ExternalNetworkId}, validator_sets::primitives::{Session, KeyPair}, }; @@ -736,19 +736,23 @@ async fn main() { "http://".to_string() + &login + "@" + &hostname + ":" + &port }; let network_id = match env::var("NETWORK").expect("network wasn't specified").as_str() { - "bitcoin" => NetworkId::Bitcoin, - "ethereum" => NetworkId::Ethereum, - "monero" => NetworkId::Monero, + "bitcoin" => ExternalNetworkId::Bitcoin, + "ethereum" => ExternalNetworkId::Ethereum, + "monero" => ExternalNetworkId::Monero, _ => panic!("unrecognized network"), }; let coordinator = MessageQueue::from_env(Service::Processor(network_id)); + // This allow is necessary since each configuration deletes the other networks from the following + // match arms. So we match all cases but since all cases already there according to the compiler + // we put this to allow clippy to get pass this. + #[allow(unreachable_patterns)] match network_id { #[cfg(feature = "bitcoin")] - NetworkId::Bitcoin => run(db, Bitcoin::new(url).await, coordinator).await, + ExternalNetworkId::Bitcoin => run(db, Bitcoin::new(url).await, coordinator).await, #[cfg(feature = "ethereum")] - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { let relayer_hostname = env::var("ETHEREUM_RELAYER_HOSTNAME") .expect("ethereum relayer hostname wasn't specified") .to_string(); @@ -758,7 +762,7 @@ async fn main() { run(db.clone(), Ethereum::new(db, url, relayer_url).await, coordinator).await } #[cfg(feature = "monero")] - NetworkId::Monero => run(db, Monero::new(url).await, coordinator).await, + ExternalNetworkId::Monero => run(db, Monero::new(url).await, coordinator).await, _ => panic!("spawning a processor for an unsupported network"), } } diff --git a/processor/src/multisigs/db.rs b/processor/src/multisigs/db.rs index 3d1d13bdf..f5e05f683 100644 --- a/processor/src/multisigs/db.rs +++ b/processor/src/multisigs/db.rs @@ -4,7 +4,11 @@ use ciphersuite::Ciphersuite; pub use serai_db::*; use scale::{Encode, Decode}; -use serai_client::{primitives::Balance, in_instructions::primitives::InInstructionWithBalance}; +#[rustfmt::skip] +use serai_client::{ + in_instructions::primitives::InInstructionWithBalance, + primitives::ExternalBalance +}; use crate::{ Get, Plan, @@ -69,7 +73,7 @@ create_db!( OperatingCostsDb: () -> u64, ResolvedDb: (tx: &[u8]) -> [u8; 32], SigningDb: (key: &[u8]) -> Vec, - ForwardedOutputDb: (balance: Balance) -> Vec, + ForwardedOutputDb: (balance: ExternalBalance) -> Vec, DelayedOutputDb: () -> Vec } ); @@ -224,7 +228,7 @@ impl ForwardedOutputDb { pub fn take_forwarded_output( txn: &mut impl DbTxn, - balance: Balance, + balance: ExternalBalance, ) -> Option { let outputs = Self::get(txn, balance)?; let mut outputs_ref = outputs.as_slice(); diff --git a/processor/src/multisigs/scheduler/mod.rs b/processor/src/multisigs/scheduler/mod.rs index 26c940fe8..b34e2f3e6 100644 --- a/processor/src/multisigs/scheduler/mod.rs +++ b/processor/src/multisigs/scheduler/mod.rs @@ -3,7 +3,7 @@ use std::io; use ciphersuite::Ciphersuite; -use serai_client::primitives::{NetworkId, Balance}; +use serai_client::primitives::{ExternalBalance, ExternalNetworkId}; use crate::{networks::Network, Db, Payment, Plan}; @@ -34,18 +34,18 @@ pub trait Scheduler: Sized + Clone + PartialEq + Debug { fn new( txn: &mut D::Transaction<'_>, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> Self; /// Load a Scheduler from the DB. fn from_db( db: &D, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> io::Result; /// Check if a branch is usable. - fn can_use_branch(&self, balance: Balance) -> bool; + fn can_use_branch(&self, balance: ExternalBalance) -> bool; /// Schedule a series of outputs/payments. fn schedule( diff --git a/processor/src/multisigs/scheduler/smart_contract.rs b/processor/src/multisigs/scheduler/smart_contract.rs index 3da8acf48..a6bbbdaf0 100644 --- a/processor/src/multisigs/scheduler/smart_contract.rs +++ b/processor/src/multisigs/scheduler/smart_contract.rs @@ -2,7 +2,7 @@ use std::{io, collections::HashSet}; use ciphersuite::{group::GroupEncoding, Ciphersuite}; -use serai_client::primitives::{NetworkId, Coin, Balance}; +use serai_client::primitives::{ExternalBalance, ExternalCoin, ExternalNetworkId}; use crate::{ Get, DbTxn, Db, Payment, Plan, create_db, @@ -13,7 +13,7 @@ use crate::{ #[derive(Clone, PartialEq, Eq, Debug)] pub struct Scheduler { key: ::G, - coins: HashSet, + coins: HashSet, rotated: bool, } @@ -78,7 +78,7 @@ impl> SchedulerTrait for Scheduler { fn new( _txn: &mut D::Transaction<'_>, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> Self { assert!(N::branch_address(key).is_none()); assert!(N::change_address(key).is_none()); @@ -91,7 +91,7 @@ impl> SchedulerTrait for Scheduler { fn from_db( db: &D, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> io::Result { Ok(Scheduler { key, @@ -100,7 +100,7 @@ impl> SchedulerTrait for Scheduler { }) } - fn can_use_branch(&self, _balance: Balance) -> bool { + fn can_use_branch(&self, _balance: ExternalBalance) -> bool { false } diff --git a/processor/src/multisigs/scheduler/utxo.rs b/processor/src/multisigs/scheduler/utxo.rs index 1865cab91..3758e54c1 100644 --- a/processor/src/multisigs/scheduler/utxo.rs +++ b/processor/src/multisigs/scheduler/utxo.rs @@ -5,7 +5,7 @@ use std::{ use ciphersuite::{group::GroupEncoding, Ciphersuite}; -use serai_client::primitives::{NetworkId, Coin, Amount, Balance}; +use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount, ExternalBalance}; use crate::{ DbTxn, Db, Payment, Plan, @@ -17,7 +17,7 @@ use crate::{ #[derive(Clone, PartialEq, Eq, Debug)] pub struct Scheduler { key: ::G, - coin: Coin, + coin: ExternalCoin, // Serai, when it has more outputs expected than it can handle in a single transaction, will // schedule the outputs to be handled later. Immediately, it just creates additional outputs @@ -57,7 +57,7 @@ impl> Scheduler { fn read( key: ::G, - coin: Coin, + coin: ExternalCoin, reader: &mut R, ) -> io::Result { let mut read_plans = || -> io::Result<_> { @@ -145,7 +145,7 @@ impl> Scheduler { pub fn new( txn: &mut D::Transaction<'_>, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> Self { assert!(N::branch_address(key).is_some()); assert!(N::change_address(key).is_some()); @@ -173,7 +173,7 @@ impl> Scheduler { pub fn from_db( db: &D, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> io::Result { let coin = { let coins = network.coins(); @@ -190,7 +190,7 @@ impl> Scheduler { Self::read(key, coin, reader) } - pub fn can_use_branch(&self, balance: Balance) -> bool { + pub fn can_use_branch(&self, balance: ExternalBalance) -> bool { assert_eq!(balance.coin, self.coin); self.plans.contains_key(&balance.amount.0) } @@ -249,7 +249,7 @@ impl> Scheduler { Payment { address: branch_address.clone(), data: None, - balance: Balance { coin: self.coin, amount: Amount(amount) }, + balance: ExternalBalance { coin: self.coin, amount: Amount(amount) }, }, ); } @@ -536,7 +536,7 @@ impl> SchedulerTrait for Scheduler { fn new( txn: &mut D::Transaction<'_>, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> Self { Scheduler::new::(txn, key, network) } @@ -545,13 +545,13 @@ impl> SchedulerTrait for Scheduler { fn from_db( db: &D, key: ::G, - network: NetworkId, + network: ExternalNetworkId, ) -> io::Result { Scheduler::from_db::(db, key, network) } /// Check if a branch is usable. - fn can_use_branch(&self, balance: Balance) -> bool { + fn can_use_branch(&self, balance: ExternalBalance) -> bool { Scheduler::can_use_branch(self, balance) } @@ -574,7 +574,7 @@ impl> SchedulerTrait for Scheduler { /// Note a branch output as having been created, with the amount it was actually created with, /// or not having been created due to being too small. - // TODO: Move this to Balance. + // TODO: Move this to ExternalBalance. fn created_output( &mut self, txn: &mut D::Transaction<'_>, diff --git a/processor/src/networks/bitcoin.rs b/processor/src/networks/bitcoin.rs index 14b30bde7..5702f5ed9 100644 --- a/processor/src/networks/bitcoin.rs +++ b/processor/src/networks/bitcoin.rs @@ -42,7 +42,7 @@ use bitcoin_serai::bitcoin::{ }; use serai_client::{ - primitives::{MAX_DATA_LEN, Coin, NetworkId, Amount, Balance}, + primitives::{MAX_DATA_LEN, ExternalCoin, ExternalNetworkId, Amount, ExternalBalance}, networks::bitcoin::Address, }; @@ -125,8 +125,8 @@ impl OutputTrait for Output { self.presumed_origin.clone() } - fn balance(&self) -> Balance { - Balance { coin: Coin::Bitcoin, amount: Amount(self.output.value()) } + fn balance(&self) -> ExternalBalance { + ExternalBalance { coin: ExternalCoin::Bitcoin, amount: Amount(self.output.value()) } } fn data(&self) -> &[u8] { @@ -423,7 +423,7 @@ impl Bitcoin { calculating_fee: bool, ) -> Result, NetworkError> { for payment in payments { - assert_eq!(payment.balance.coin, Coin::Bitcoin); + assert_eq!(payment.balance.coin, ExternalCoin::Bitcoin); } // TODO2: Use an fee representative of several blocks, cached inside Self @@ -598,7 +598,7 @@ impl Network for Bitcoin { type Address = Address; - const NETWORK: NetworkId = NetworkId::Bitcoin; + const NETWORK: ExternalNetworkId = ExternalNetworkId::Bitcoin; const ID: &'static str = "Bitcoin"; const ESTIMATED_BLOCK_TIME_IN_SECONDS: usize = 600; const CONFIRMATIONS: usize = 6; diff --git a/processor/src/networks/ethereum.rs b/processor/src/networks/ethereum.rs index 3545f34ac..49c4bc61c 100644 --- a/processor/src/networks/ethereum.rs +++ b/processor/src/networks/ethereum.rs @@ -38,7 +38,7 @@ use tokio::{ }; use serai_client::{ - primitives::{Coin, Amount, Balance, NetworkId}, + primitives::{ExternalCoin, Amount, ExternalBalance, ExternalNetworkId}, validator_sets::primitives::Session, }; @@ -68,20 +68,20 @@ const DAI: [u8; 20] = Err(_) => panic!("invalid test DAI hex address"), }; -fn coin_to_serai_coin(coin: &EthereumCoin) -> Option { +fn coin_to_serai_coin(coin: &EthereumCoin) -> Option { match coin { - EthereumCoin::Ether => Some(Coin::Ether), + EthereumCoin::Ether => Some(ExternalCoin::Ether), EthereumCoin::Erc20(token) => { if *token == DAI { - return Some(Coin::Dai); + return Some(ExternalCoin::Dai); } None } } } -fn amount_to_serai_amount(coin: Coin, amount: U256) -> Amount { - assert_eq!(coin.network(), NetworkId::Ethereum); +fn amount_to_serai_amount(coin: ExternalCoin, amount: U256) -> Amount { + assert_eq!(coin.network(), ExternalNetworkId::Ethereum); assert_eq!(coin.decimals(), 8); // Remove 10 decimals so we go from 18 decimals to 8 decimals let divisor = U256::from(10_000_000_000u64); @@ -89,8 +89,8 @@ fn amount_to_serai_amount(coin: Coin, amount: U256) -> Amount { Amount(u64::try_from(amount / divisor).unwrap()) } -fn balance_to_ethereum_amount(balance: Balance) -> U256 { - assert_eq!(balance.coin.network(), NetworkId::Ethereum); +fn balance_to_ethereum_amount(balance: ExternalBalance) -> U256 { + assert_eq!(balance.coin.network(), ExternalNetworkId::Ethereum); assert_eq!(balance.coin.decimals(), 8); // Restore 10 decimals so we go from 8 decimals to 18 decimals let factor = U256::from(10_000_000_000u64); @@ -201,14 +201,14 @@ impl Output> for EthereumInInstruction { Some(Address(self.from)) } - fn balance(&self) -> Balance { + fn balance(&self) -> ExternalBalance { let coin = coin_to_serai_coin(&self.coin).unwrap_or_else(|| { panic!( "requesting coin for an EthereumInInstruction with a coin {}", "we don't handle. this never should have been yielded" ) }); - Balance { coin, amount: amount_to_serai_amount(coin, self.amount) } + ExternalBalance { coin, amount: amount_to_serai_amount(coin, self.amount) } } fn data(&self) -> &[u8] { &self.data @@ -394,7 +394,7 @@ impl Network for Ethereum { type Address = Address; - const NETWORK: NetworkId = NetworkId::Ethereum; + const NETWORK: ExternalNetworkId = ExternalNetworkId::Ethereum; const ID: &'static str = "Ethereum"; const ESTIMATED_BLOCK_TIME_IN_SECONDS: usize = 32 * 12; const CONFIRMATIONS: usize = 1; @@ -681,7 +681,7 @@ impl Network for Ethereum { OutInstructionTarget::Direct(payment.address.0) }, value: { - assert_eq!(payment.balance.coin, Coin::Ether); // TODO + assert_eq!(payment.balance.coin, ExternalCoin::Ether); // TODO balance_to_ethereum_amount(payment.balance) }, }) diff --git a/processor/src/networks/mod.rs b/processor/src/networks/mod.rs index ee3cd24af..9cfeff89c 100644 --- a/processor/src/networks/mod.rs +++ b/processor/src/networks/mod.rs @@ -10,7 +10,7 @@ use frost::{ sign::PreprocessMachine, }; -use serai_client::primitives::{NetworkId, Balance}; +use serai_client::primitives::{ExternalBalance, ExternalNetworkId}; use log::error; @@ -115,7 +115,7 @@ pub trait Output: Send + Sync + Sized + Clone + PartialEq + Eq + Deb fn presumed_origin(&self) -> Option; - fn balance(&self) -> Balance; + fn balance(&self) -> ExternalBalance; fn data(&self) -> &[u8]; fn write(&self, writer: &mut W) -> io::Result<()>; @@ -126,13 +126,13 @@ pub trait Output: Send + Sync + Sized + Clone + PartialEq + Eq + Deb pub trait Transaction: Send + Sync + Sized + Clone + PartialEq + Debug { type Id: 'static + Id; fn id(&self) -> Self::Id; - // TODO: Move to Balance + // TODO: Move to ExternalBalance #[cfg(test)] async fn fee(&self, network: &N) -> u64; } pub trait SignableTransaction: Send + Sync + Clone + Debug { - // TODO: Move to Balance + // TODO: Move to ExternalBalance fn fee(&self) -> u64; } @@ -280,7 +280,7 @@ pub trait Network: 'static + Send + Sync + Clone + PartialEq + Debug { + TryFrom>; /// Network ID for this network. - const NETWORK: NetworkId; + const NETWORK: ExternalNetworkId; /// String ID for this network. const ID: &'static str; /// The estimated amount of time a block will take. @@ -297,7 +297,7 @@ pub trait Network: 'static + Send + Sync + Clone + PartialEq + Debug { /// For any received output, there's the cost to spend the output. This value MUST exceed the /// cost to spend said output, and should by a notable margin (not just 2x, yet an order of /// magnitude). - // TODO: Dust needs to be diversified per Coin + // TODO: Dust needs to be diversified per ExternalCoin const DUST: u64; /// The cost to perform input aggregation with a 2-input 1-output TX. diff --git a/processor/src/networks/monero.rs b/processor/src/networks/monero.rs index 154702fef..4e70c0025 100644 --- a/processor/src/networks/monero.rs +++ b/processor/src/networks/monero.rs @@ -31,7 +31,7 @@ use monero_wallet::Scanner; use tokio::time::sleep; pub use serai_client::{ - primitives::{MAX_DATA_LEN, Coin, NetworkId, Amount, Balance}, + primitives::{MAX_DATA_LEN, ExternalCoin, ExternalNetworkId, Amount, ExternalBalance}, networks::monero::Address, }; @@ -85,8 +85,8 @@ impl OutputTrait for Output { None } - fn balance(&self) -> Balance { - Balance { coin: Coin::Monero, amount: Amount(self.0.commitment().amount) } + fn balance(&self) -> ExternalBalance { + ExternalBalance { coin: ExternalCoin::Monero, amount: Amount(self.0.commitment().amount) } } fn data(&self) -> &[u8] { @@ -308,7 +308,7 @@ impl Monero { calculating_fee: bool, ) -> Result, NetworkError> { for payment in payments { - assert_eq!(payment.balance.coin, Coin::Monero); + assert_eq!(payment.balance.coin, ExternalCoin::Monero); } // TODO2: Use an fee representative of several blocks, cached inside Self @@ -363,7 +363,7 @@ impl Monero { .legacy_address(MoneroNetwork::Mainnet), ) .unwrap(), - balance: Balance { coin: Coin::Monero, amount: Amount(0) }, + balance: ExternalBalance { coin: ExternalCoin::Monero, amount: Amount(0) }, data: None, }); } @@ -470,7 +470,7 @@ impl Network for Monero { type Address = Address; - const NETWORK: NetworkId = NetworkId::Monero; + const NETWORK: ExternalNetworkId = ExternalNetworkId::Monero; const ID: &'static str = "Monero"; const ESTIMATED_BLOCK_TIME_IN_SECONDS: usize = 120; const CONFIRMATIONS: usize = 10; diff --git a/processor/src/plan.rs b/processor/src/plan.rs index 58a8a5e11..caadef5ae 100644 --- a/processor/src/plan.rs +++ b/processor/src/plan.rs @@ -6,7 +6,7 @@ use transcript::{Transcript, RecommendedTranscript}; use ciphersuite::group::GroupEncoding; use frost::curve::Ciphersuite; -use serai_client::primitives::Balance; +use serai_client::primitives::ExternalBalance; use crate::{ networks::{Output, Network}, @@ -17,7 +17,7 @@ use crate::{ pub struct Payment { pub address: N::Address, pub data: Option>, - pub balance: Balance, + pub balance: ExternalBalance, } impl Payment { @@ -69,7 +69,7 @@ impl Payment { None }; - let balance = Balance::decode(&mut scale::IoReader(reader)) + let balance = ExternalBalance::decode(&mut scale::IoReader(reader)) .map_err(|_| io::Error::other("invalid balance"))?; Ok(Payment { address, data, balance }) diff --git a/processor/src/slash_report_signer.rs b/processor/src/slash_report_signer.rs index b7b2d55ce..056055f7c 100644 --- a/processor/src/slash_report_signer.rs +++ b/processor/src/slash_report_signer.rs @@ -17,9 +17,9 @@ use frost_schnorrkel::Schnorrkel; use log::{info, warn}; use serai_client::{ + primitives::ExternalNetworkId, + validator_sets::primitives::{report_slashes_message, ExternalValidatorSet, Session}, Public, - primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet, report_slashes_message}, }; use messages::coordinator::*; @@ -38,7 +38,7 @@ type SignatureShare = as SignMachin >>::SignatureShare; pub struct SlashReportSigner { - network: NetworkId, + network: ExternalNetworkId, session: Session, keys: Vec>, report: Vec<([u8; 32], u32)>, @@ -66,7 +66,7 @@ impl fmt::Debug for SlashReportSigner { impl SlashReportSigner { pub fn new( txn: &mut impl DbTxn, - network: NetworkId, + network: ExternalNetworkId, session: Session, keys: Vec>, report: Vec<([u8; 32], u32)>, @@ -178,7 +178,7 @@ impl SlashReportSigner { let (machine, share) = match machine.sign( preprocesses, &report_slashes_message( - &ValidatorSet { network: self.network, session: self.session }, + &ExternalValidatorSet { network: self.network, session: self.session }, &self .report .clone() diff --git a/processor/src/tests/batch_signer.rs b/processor/src/tests/batch_signer.rs index dc45ff312..8da67ef13 100644 --- a/processor/src/tests/batch_signer.rs +++ b/processor/src/tests/batch_signer.rs @@ -33,17 +33,17 @@ fn test_batch_signer() { let block = BlockHash([0xaa; 32]); let batch = Batch { - network: NetworkId::Monero, + network: ExternalNetworkId::Monero, id, block, instructions: vec![ InInstructionWithBalance { instruction: InInstruction::Transfer(SeraiAddress([0xbb; 32])), - balance: Balance { coin: Coin::Bitcoin, amount: Amount(1000) }, + balance: ExternalBalance { coin: ExternalCoin::Bitcoin, amount: Amount(1000) }, }, InInstructionWithBalance { instruction: InInstruction::Dex(DexCall::SwapAndAddLiquidity(SeraiAddress([0xbb; 32]))), - balance: Balance { coin: Coin::Monero, amount: Amount(9999999999999999) }, + balance: ExternalBalance { coin: ExternalCoin::Monero, amount: Amount(9999999999999999) }, }, ], }; @@ -70,7 +70,7 @@ fn test_batch_signer() { let i = Participant::new(u16::try_from(i).unwrap()).unwrap(); let keys = keys.get(&i).unwrap().clone(); - let mut signer = BatchSigner::::new(NetworkId::Monero, Session(0), vec![keys]); + let mut signer = BatchSigner::::new(ExternalNetworkId::Monero, Session(0), vec![keys]); let mut db = MemDb::new(); let mut txn = db.txn(); diff --git a/processor/src/tests/signer.rs b/processor/src/tests/signer.rs index 77307ef26..26b26b35e 100644 --- a/processor/src/tests/signer.rs +++ b/processor/src/tests/signer.rs @@ -12,7 +12,7 @@ use frost::{ use serai_db::{DbTxn, Db, MemDb}; use serai_client::{ - primitives::{NetworkId, Coin, Amount, Balance}, + primitives::{ExternalNetworkId, ExternalCoin, Amount, ExternalBalance}, validator_sets::primitives::Session, }; @@ -185,12 +185,11 @@ pub async fn test_signer( let payments = vec![Payment { address: N::external_address(&network, key).await, data: None, - balance: Balance { + balance: ExternalBalance { coin: match N::NETWORK { - NetworkId::Serai => panic!("test_signer called with Serai"), - NetworkId::Bitcoin => Coin::Bitcoin, - NetworkId::Ethereum => Coin::Ether, - NetworkId::Monero => Coin::Monero, + ExternalNetworkId::Bitcoin => ExternalCoin::Bitcoin, + ExternalNetworkId::Ethereum => ExternalCoin::Ether, + ExternalNetworkId::Monero => ExternalCoin::Monero, }, amount: Amount(amount), }, @@ -224,7 +223,7 @@ pub async fn test_signer( .await; // Don't run if Ethereum as the received output will revert by the contract // (and therefore not actually exist) - if N::NETWORK != NetworkId::Ethereum { + if N::NETWORK != ExternalNetworkId::Ethereum { assert_eq!(outputs.len(), 1 + usize::from(u8::from(plan.change.is_some()))); // Adjust the amount for the fees let amount = amount - tx.fee(&network).await; diff --git a/processor/src/tests/wallet.rs b/processor/src/tests/wallet.rs index 86a27349d..74d7ccc0f 100644 --- a/processor/src/tests/wallet.rs +++ b/processor/src/tests/wallet.rs @@ -11,7 +11,7 @@ use tokio::time::timeout; use serai_db::{DbTxn, Db, MemDb}; use serai_client::{ - primitives::{NetworkId, Coin, Amount, Balance}, + primitives::{ExternalNetworkId, ExternalCoin, Amount, ExternalBalance}, validator_sets::primitives::Session, }; @@ -89,12 +89,11 @@ pub async fn test_wallet( vec![Payment { address: N::external_address(&network, key).await, data: None, - balance: Balance { + balance: ExternalBalance { coin: match N::NETWORK { - NetworkId::Serai => panic!("test_wallet called with Serai"), - NetworkId::Bitcoin => Coin::Bitcoin, - NetworkId::Ethereum => Coin::Ether, - NetworkId::Monero => Coin::Monero, + ExternalNetworkId::Bitcoin => ExternalCoin::Bitcoin, + ExternalNetworkId::Ethereum => ExternalCoin::Ether, + ExternalNetworkId::Monero => ExternalCoin::Monero, }, amount: Amount(amount), }, @@ -117,12 +116,11 @@ pub async fn test_wallet( vec![Payment { address: N::external_address(&network, key).await, data: None, - balance: Balance { + balance: ExternalBalance { coin: match N::NETWORK { - NetworkId::Serai => panic!("test_wallet called with Serai"), - NetworkId::Bitcoin => Coin::Bitcoin, - NetworkId::Ethereum => Coin::Ether, - NetworkId::Monero => Coin::Monero, + ExternalNetworkId::Bitcoin => ExternalCoin::Bitcoin, + ExternalNetworkId::Ethereum => ExternalCoin::Ether, + ExternalNetworkId::Monero => ExternalCoin::Monero, }, amount: Amount(amount), } @@ -160,7 +158,7 @@ pub async fn test_wallet( // Don't run if Ethereum as the received output will revert by the contract // (and therefore not actually exist) - if N::NETWORK != NetworkId::Ethereum { + if N::NETWORK != ExternalNetworkId::Ethereum { assert_eq!(outputs.len(), 1 + usize::from(u8::from(plans[0].change.is_some()))); // Adjust the amount for the fees let amount = amount - tx.fee(&network).await; @@ -183,7 +181,7 @@ pub async fn test_wallet( network.mine_block().await; } - if N::NETWORK != NetworkId::Ethereum { + if N::NETWORK != ExternalNetworkId::Ethereum { match timeout(Duration::from_secs(30), scanner.events.recv()).await.unwrap().unwrap() { ScannerEvent::Block { is_retirement_block, block: block_id, outputs: these_outputs } => { scanner.multisig_completed.send(false).unwrap(); diff --git a/substrate/abi/src/dex.rs b/substrate/abi/src/dex.rs index 2daa62f07..d85dace3d 100644 --- a/substrate/abi/src/dex.rs +++ b/substrate/abi/src/dex.rs @@ -2,7 +2,7 @@ use sp_runtime::BoundedVec; use serai_primitives::*; -type PoolId = Coin; +type PoolId = ExternalCoin; type MaxSwapPathLength = sp_core::ConstU32<3>; #[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)] @@ -10,7 +10,7 @@ type MaxSwapPathLength = sp_core::ConstU32<3>; #[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))] pub enum Call { add_liquidity { - coin: Coin, + coin: ExternalCoin, coin_desired: SubstrateAmount, sri_desired: SubstrateAmount, coin_min: SubstrateAmount, @@ -18,7 +18,7 @@ pub enum Call { mint_to: SeraiAddress, }, remove_liquidity { - coin: Coin, + coin: ExternalCoin, lp_token_burn: SubstrateAmount, coin_min_receive: SubstrateAmount, sri_min_receive: SubstrateAmount, diff --git a/substrate/abi/src/economic_security.rs b/substrate/abi/src/economic_security.rs index fc548def9..2899e0908 100644 --- a/substrate/abi/src/economic_security.rs +++ b/substrate/abi/src/economic_security.rs @@ -1,8 +1,8 @@ -use serai_primitives::NetworkId; +use serai_primitives::ExternalNetworkId; #[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Event { - EconomicSecurityReached { network: NetworkId }, + EconomicSecurityReached { network: ExternalNetworkId }, } diff --git a/substrate/abi/src/genesis_liquidity.rs b/substrate/abi/src/genesis_liquidity.rs index 461284141..7660b3ab6 100644 --- a/substrate/abi/src/genesis_liquidity.rs +++ b/substrate/abi/src/genesis_liquidity.rs @@ -6,7 +6,7 @@ use primitives::*; #[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Call { - remove_coin_liquidity { balance: Balance }, + remove_coin_liquidity { balance: ExternalBalance }, oraclize_values { values: Values, signature: Signature }, } @@ -14,8 +14,7 @@ pub enum Call { #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Event { - GenesisLiquidityAdded { by: SeraiAddress, balance: Balance }, - GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance }, - GenesisLiquidityAddedToPool { coin1: Balance, coin2: Balance }, - EconomicSecurityReached { network: NetworkId }, + GenesisLiquidityAdded { by: SeraiAddress, balance: ExternalBalance }, + GenesisLiquidityRemoved { by: SeraiAddress, balance: ExternalBalance }, + GenesisLiquidityAddedToPool { coin: ExternalBalance, sri: Amount }, } diff --git a/substrate/abi/src/in_instructions.rs b/substrate/abi/src/in_instructions.rs index d3ab5ca3d..765a50531 100644 --- a/substrate/abi/src/in_instructions.rs +++ b/substrate/abi/src/in_instructions.rs @@ -16,7 +16,7 @@ pub enum Call { #[cfg_attr(feature = "serde", derive(serde::Serialize))] #[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))] pub enum Event { - Batch { network: NetworkId, id: u32, block: BlockHash, instructions_hash: [u8; 32] }, - InstructionFailure { network: NetworkId, id: u32, index: u32 }, - Halt { network: NetworkId }, + Batch { network: ExternalNetworkId, id: u32, block: BlockHash, instructions_hash: [u8; 32] }, + InstructionFailure { network: ExternalNetworkId, id: u32, index: u32 }, + Halt { network: ExternalNetworkId }, } diff --git a/substrate/abi/src/validator_sets.rs b/substrate/abi/src/validator_sets.rs index 1e1e33591..8e7d2e1e8 100644 --- a/substrate/abi/src/validator_sets.rs +++ b/substrate/abi/src/validator_sets.rs @@ -10,13 +10,13 @@ use serai_validator_sets_primitives::*; #[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))] pub enum Call { set_keys { - network: NetworkId, + network: ExternalNetworkId, removed_participants: BoundedVec>, key_pair: KeyPair, signature: Signature, }, report_slashes { - network: NetworkId, + network: ExternalNetworkId, slashes: BoundedVec<(SeraiAddress, u32), ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>, signature: Signature, }, @@ -47,7 +47,7 @@ pub enum Event { removed: SeraiAddress, }, KeyGen { - set: ValidatorSet, + set: ExternalValidatorSet, key_pair: KeyPair, }, AcceptedHandover { diff --git a/substrate/client/src/serai/dex.rs b/substrate/client/src/serai/dex.rs index ea76e6258..1c44107fe 100644 --- a/substrate/client/src/serai/dex.rs +++ b/substrate/client/src/serai/dex.rs @@ -1,5 +1,5 @@ use sp_core::bounded_vec::BoundedVec; -use serai_abi::primitives::{SeraiAddress, Amount, Coin}; +use serai_abi::primitives::{Amount, Coin, ExternalCoin, SeraiAddress}; use crate::{SeraiError, TemporalSerai}; @@ -20,7 +20,7 @@ impl<'a> SeraiDex<'a> { } pub fn add_liquidity( - coin: Coin, + coin: ExternalCoin, coin_amount: Amount, sri_amount: Amount, min_coin_amount: Amount, @@ -61,11 +61,14 @@ impl<'a> SeraiDex<'a> { } /// Returns the reserves of `coin:SRI` pool. - pub async fn get_reserves(&self, coin: Coin) -> Result, SeraiError> { - self.0.runtime_api("DexApi_get_reserves", (coin, Coin::Serai)).await + pub async fn get_reserves( + &self, + coin: ExternalCoin, + ) -> Result, SeraiError> { + self.0.runtime_api("DexApi_get_reserves", (Coin::from(coin), Coin::Serai)).await } - pub async fn oracle_value(&self, coin: Coin) -> Result, SeraiError> { + pub async fn oracle_value(&self, coin: ExternalCoin) -> Result, SeraiError> { self.0.storage(PALLET, "SecurityOracleValue", coin).await } } diff --git a/substrate/client/src/serai/genesis_liquidity.rs b/substrate/client/src/serai/genesis_liquidity.rs index 187844bef..e8a152fa8 100644 --- a/substrate/client/src/serai/genesis_liquidity.rs +++ b/substrate/client/src/serai/genesis_liquidity.rs @@ -35,7 +35,7 @@ impl<'a> SeraiGenesisLiquidity<'a> { )) } - pub fn remove_coin_liquidity(balance: Balance) -> serai_abi::Call { + pub fn remove_coin_liquidity(balance: ExternalBalance) -> serai_abi::Call { serai_abi::Call::GenesisLiquidity(serai_abi::genesis_liquidity::Call::remove_coin_liquidity { balance, }) @@ -44,7 +44,7 @@ impl<'a> SeraiGenesisLiquidity<'a> { pub async fn liquidity( &self, address: &SeraiAddress, - coin: Coin, + coin: ExternalCoin, ) -> Result { Ok( self @@ -59,7 +59,7 @@ impl<'a> SeraiGenesisLiquidity<'a> { ) } - pub async fn supply(&self, coin: Coin) -> Result { + pub async fn supply(&self, coin: ExternalCoin) -> Result { Ok(self.0.storage(PALLET, "Supply", coin).await?.unwrap_or(LiquidityAmount::zero())) } diff --git a/substrate/client/src/serai/in_instructions.rs b/substrate/client/src/serai/in_instructions.rs index a8b47bfcf..d27ce695a 100644 --- a/substrate/client/src/serai/in_instructions.rs +++ b/substrate/client/src/serai/in_instructions.rs @@ -2,7 +2,7 @@ pub use serai_abi::in_instructions::primitives; use primitives::SignedBatch; use crate::{ - primitives::{BlockHash, NetworkId}, + primitives::{BlockHash, ExternalNetworkId}, Transaction, SeraiError, Serai, TemporalSerai, }; @@ -15,14 +15,14 @@ pub struct SeraiInInstructions<'a>(pub(crate) &'a TemporalSerai<'a>); impl<'a> SeraiInInstructions<'a> { pub async fn latest_block_for_network( &self, - network: NetworkId, + network: ExternalNetworkId, ) -> Result, SeraiError> { self.0.storage(PALLET, "LatestNetworkBlock", network).await } pub async fn last_batch_for_network( &self, - network: NetworkId, + network: ExternalNetworkId, ) -> Result, SeraiError> { self.0.storage(PALLET, "LastBatch", network).await } diff --git a/substrate/client/src/serai/liquidity_tokens.rs b/substrate/client/src/serai/liquidity_tokens.rs index 3e9052b2c..c7ec93cf0 100644 --- a/substrate/client/src/serai/liquidity_tokens.rs +++ b/substrate/client/src/serai/liquidity_tokens.rs @@ -1,6 +1,6 @@ use scale::Encode; -use serai_abi::primitives::{SeraiAddress, Amount, Coin, Balance}; +use serai_abi::primitives::{Amount, ExternalBalance, ExternalCoin, SeraiAddress}; use crate::{TemporalSerai, SeraiError}; @@ -9,13 +9,13 @@ const PALLET: &str = "LiquidityTokens"; #[derive(Clone, Copy)] pub struct SeraiLiquidityTokens<'a>(pub(crate) &'a TemporalSerai<'a>); impl<'a> SeraiLiquidityTokens<'a> { - pub async fn token_supply(&self, coin: Coin) -> Result { + pub async fn token_supply(&self, coin: ExternalCoin) -> Result { Ok(self.0.storage(PALLET, "Supply", coin).await?.unwrap_or(Amount(0))) } pub async fn token_balance( &self, - coin: Coin, + coin: ExternalCoin, address: SeraiAddress, ) -> Result { Ok( @@ -31,11 +31,16 @@ impl<'a> SeraiLiquidityTokens<'a> { ) } - pub fn transfer(to: SeraiAddress, balance: Balance) -> serai_abi::Call { - serai_abi::Call::LiquidityTokens(serai_abi::liquidity_tokens::Call::transfer { to, balance }) + pub fn transfer(to: SeraiAddress, balance: ExternalBalance) -> serai_abi::Call { + serai_abi::Call::LiquidityTokens(serai_abi::liquidity_tokens::Call::transfer { + to, + balance: balance.into(), + }) } - pub fn burn(balance: Balance) -> serai_abi::Call { - serai_abi::Call::LiquidityTokens(serai_abi::liquidity_tokens::Call::burn { balance }) + pub fn burn(balance: ExternalBalance) -> serai_abi::Call { + serai_abi::Call::LiquidityTokens(serai_abi::liquidity_tokens::Call::burn { + balance: balance.into(), + }) } } diff --git a/substrate/client/src/serai/validator_sets.rs b/substrate/client/src/serai/validator_sets.rs index ec67bae0f..5bfb3ed53 100644 --- a/substrate/client/src/serai/validator_sets.rs +++ b/substrate/client/src/serai/validator_sets.rs @@ -2,12 +2,12 @@ use scale::Encode; use sp_core::sr25519::{Public, Signature}; -use serai_abi::primitives::Amount; +use serai_abi::{primitives::Amount, validator_sets::primitives::ExternalValidatorSet}; pub use serai_abi::validator_sets::primitives; -use primitives::{Session, ValidatorSet, KeyPair}; +use primitives::{Session, KeyPair}; use crate::{ - primitives::{NetworkId, SeraiAddress}, + primitives::{NetworkId, ExternalNetworkId, SeraiAddress}, Transaction, Serai, TemporalSerai, SeraiError, }; @@ -167,13 +167,13 @@ impl<'a> SeraiValidatorSets<'a> { } // TODO: Store these separately since we almost never need both at once? - pub async fn keys(&self, set: ValidatorSet) -> Result, SeraiError> { + pub async fn keys(&self, set: ExternalValidatorSet) -> Result, SeraiError> { self.0.storage(PALLET, "Keys", (sp_core::hashing::twox_64(&set.encode()), set)).await } pub async fn key_pending_slash_report( &self, - network: NetworkId, + network: ExternalNetworkId, ) -> Result, SeraiError> { self.0.storage(PALLET, "PendingSlashReport", network).await } @@ -187,7 +187,7 @@ impl<'a> SeraiValidatorSets<'a> { } pub fn set_keys( - network: NetworkId, + network: ExternalNetworkId, removed_participants: sp_runtime::BoundedVec< SeraiAddress, sp_core::ConstU32<{ primitives::MAX_KEY_SHARES_PER_SET / 3 }>, @@ -212,7 +212,7 @@ impl<'a> SeraiValidatorSets<'a> { } pub fn report_slashes( - network: NetworkId, + network: ExternalNetworkId, slashes: sp_runtime::BoundedVec< (SeraiAddress, u32), sp_core::ConstU32<{ primitives::MAX_KEY_SHARES_PER_SET / 3 }>, diff --git a/substrate/client/tests/batch.rs b/substrate/client/tests/batch.rs index 17e4d3744..1a5b38667 100644 --- a/substrate/client/tests/batch.rs +++ b/substrate/client/tests/batch.rs @@ -8,7 +8,7 @@ use blake2::{ use scale::Encode; use serai_client::{ - primitives::{Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress}, + primitives::{Amount, BlockHash, ExternalBalance, ExternalCoin, SeraiAddress}, in_instructions::{ primitives::{InInstruction, InInstructionWithBalance, Batch}, InInstructionsEvent, @@ -22,18 +22,17 @@ use common::in_instructions::provide_batch; serai_test!( publish_batch: (|serai: Serai| async move { - let network = NetworkId::Bitcoin; let id = 0; - let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); let mut address = SeraiAddress::new([0; 32]); OsRng.fill_bytes(&mut address.0); - let coin = Coin::Bitcoin; + let coin = ExternalCoin::Bitcoin; + let network = coin.network(); let amount = Amount(OsRng.next_u64().saturating_add(1)); - let balance = Balance { coin, amount }; + let balance = ExternalBalance { coin, amount }; let batch = Batch { network, @@ -67,9 +66,9 @@ serai_test!( let serai = serai.coins(); assert_eq!( serai.mint_events().await.unwrap(), - vec![CoinsEvent::Mint { to: address, balance }] + vec![CoinsEvent::Mint { to: address, balance: balance.into() }] ); - assert_eq!(serai.coin_supply(coin).await.unwrap(), amount); - assert_eq!(serai.coin_balance(coin, address).await.unwrap(), amount); + assert_eq!(serai.coin_supply(coin.into()).await.unwrap(), amount); + assert_eq!(serai.coin_balance(coin.into(), address).await.unwrap(), amount); }) ); diff --git a/substrate/client/tests/burn.rs b/substrate/client/tests/burn.rs index a30dabec1..3dc0c1277 100644 --- a/substrate/client/tests/burn.rs +++ b/substrate/client/tests/burn.rs @@ -12,7 +12,7 @@ use sp_core::Pair; use serai_client::{ primitives::{ - Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, Data, ExternalAddress, + Amount, ExternalCoin, ExternalBalance, BlockHash, SeraiAddress, Data, ExternalAddress, insecure_pair_from_name, }, in_instructions::{ @@ -28,9 +28,7 @@ use common::{tx::publish_tx, in_instructions::provide_batch}; serai_test!( burn: (|serai: Serai| async move { - let network = NetworkId::Bitcoin; let id = 0; - let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); @@ -38,9 +36,10 @@ serai_test!( let public = pair.public(); let address = SeraiAddress::from(public); - let coin = Coin::Bitcoin; + let coin = ExternalCoin::Bitcoin; + let network = coin.network(); let amount = Amount(OsRng.next_u64().saturating_add(1)); - let balance = Balance { coin, amount }; + let balance = ExternalBalance { coin, amount }; let batch = Batch { network, @@ -69,10 +68,10 @@ serai_test!( assert_eq!( serai.coins().mint_events().await.unwrap(), - vec![CoinsEvent::Mint { to: address, balance }] + vec![CoinsEvent::Mint { to: address, balance: balance.into() }] ); - assert_eq!(serai.coins().coin_supply(coin).await.unwrap(), amount); - assert_eq!(serai.coins().coin_balance(coin, address).await.unwrap(), amount); + assert_eq!(serai.coins().coin_supply(coin.into()).await.unwrap(), amount); + assert_eq!(serai.coins().coin_balance(coin.into(), address).await.unwrap(), amount); // Now burn it let mut rand_bytes = vec![0; 32]; @@ -99,7 +98,7 @@ serai_test!( let serai = serai.coins(); let events = serai.burn_with_instruction_events().await.unwrap(); assert_eq!(events, vec![CoinsEvent::BurnWithInstruction { from: address, instruction }]); - assert_eq!(serai.coin_supply(coin).await.unwrap(), Amount(0)); - assert_eq!(serai.coin_balance(coin, address).await.unwrap(), Amount(0)); + assert_eq!(serai.coin_supply(coin.into()).await.unwrap(), Amount(0)); + assert_eq!(serai.coin_balance(coin.into(), address).await.unwrap(), Amount(0)); }) ); diff --git a/substrate/client/tests/common/dex.rs b/substrate/client/tests/common/dex.rs index 86e536917..a5ea25189 100644 --- a/substrate/client/tests/common/dex.rs +++ b/substrate/client/tests/common/dex.rs @@ -1,4 +1,4 @@ -use serai_abi::primitives::{Coin, Amount}; +use serai_abi::primitives::{Amount, Coin, ExternalCoin}; use serai_client::{Serai, SeraiDex}; use sp_core::{sr25519::Pair, Pair as PairTrait}; @@ -8,7 +8,7 @@ use crate::common::tx::publish_tx; #[allow(dead_code)] pub async fn add_liquidity( serai: &Serai, - coin: Coin, + coin: ExternalCoin, coin_amount: Amount, sri_amount: Amount, nonce: u32, diff --git a/substrate/client/tests/common/genesis_liquidity.rs b/substrate/client/tests/common/genesis_liquidity.rs index 0c0cd2696..55824d368 100644 --- a/substrate/client/tests/common/genesis_liquidity.rs +++ b/substrate/client/tests/common/genesis_liquidity.rs @@ -11,11 +11,12 @@ use sp_core::{sr25519::Signature, Pair as PairTrait}; use serai_abi::{ genesis_liquidity::primitives::{oraclize_values_message, Values}, - validator_sets::primitives::{musig_context, Session, ValidatorSet}, - in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch}, + in_instructions::primitives::{Batch, InInstruction, InInstructionWithBalance}, primitives::{ - Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, insecure_pair_from_name, + insecure_pair_from_name, Amount, ExternalBalance, BlockHash, ExternalCoin, ExternalNetworkId, + NetworkId, SeraiAddress, EXTERNAL_COINS, }, + validator_sets::primitives::{musig_context, Session, ValidatorSet}, }; use serai_client::{Serai, SeraiGenesisLiquidity}; @@ -25,12 +26,11 @@ use crate::common::{in_instructions::provide_batch, tx::publish_tx}; #[allow(dead_code)] pub async fn set_up_genesis( serai: &Serai, - coins: &[Coin], - values: &HashMap, -) -> (HashMap>, HashMap) { + values: &HashMap, +) -> (HashMap>, HashMap) { // make accounts with amounts let mut accounts = HashMap::new(); - for coin in coins { + for coin in EXTERNAL_COINS { // make 5 accounts per coin let mut values = vec![]; for _ in 0 .. 5 { @@ -38,18 +38,18 @@ pub async fn set_up_genesis( OsRng.fill_bytes(&mut address.0); values.push((address, Amount(OsRng.next_u64() % 10u64.pow(coin.decimals())))); } - accounts.insert(*coin, values); + accounts.insert(coin, values); } // send a batch per coin - let mut batch_ids: HashMap = HashMap::new(); - for coin in coins { + let mut batch_ids: HashMap = HashMap::new(); + for coin in EXTERNAL_COINS { // set up instructions - let instructions = accounts[coin] + let instructions = accounts[&coin] .iter() .map(|(addr, amount)| InInstructionWithBalance { instruction: InInstruction::GenesisLiquidity(*addr), - balance: Balance { coin: *coin, amount: *amount }, + balance: ExternalBalance { coin, amount: *amount }, }) .collect::>(); @@ -73,8 +73,11 @@ pub async fn set_up_genesis( // set values relative to each other. We can do that without checking for genesis period blocks // since we are running in test(fast-epoch) mode. // TODO: Random values here - let values = - Values { monero: values[&Coin::Monero], ether: values[&Coin::Ether], dai: values[&Coin::Dai] }; + let values = Values { + monero: values[&ExternalCoin::Monero], + ether: values[&ExternalCoin::Ether], + dai: values[&ExternalCoin::Dai], + }; set_values(serai, &values).await; (accounts, batch_ids) diff --git a/substrate/client/tests/common/in_instructions.rs b/substrate/client/tests/common/in_instructions.rs index 103940abf..a87e32925 100644 --- a/substrate/client/tests/common/in_instructions.rs +++ b/substrate/client/tests/common/in_instructions.rs @@ -9,8 +9,8 @@ use scale::Encode; use sp_core::Pair; use serai_client::{ - primitives::{insecure_pair_from_name, BlockHash, NetworkId, Balance, SeraiAddress}, - validator_sets::primitives::{ValidatorSet, KeyPair}, + primitives::{insecure_pair_from_name, BlockHash, ExternalBalance, SeraiAddress}, + validator_sets::primitives::{ExternalValidatorSet, KeyPair}, in_instructions::{ primitives::{Batch, SignedBatch, batch_message, InInstruction, InInstructionWithBalance}, InInstructionsEvent, @@ -23,8 +23,8 @@ use crate::common::{tx::publish_tx, validator_sets::set_keys}; #[allow(dead_code)] pub async fn provide_batch(serai: &Serai, batch: Batch) -> [u8; 32] { let serai_latest = serai.as_of_latest_finalized_block().await.unwrap(); - let session = serai_latest.validator_sets().session(batch.network).await.unwrap().unwrap(); - let set = ValidatorSet { session, network: batch.network }; + let session = serai_latest.validator_sets().session(batch.network.into()).await.unwrap().unwrap(); + let set = ExternalValidatorSet { session, network: batch.network }; let pair = insecure_pair_from_name(&format!("ValidatorSet {set:?}")); let keys = if let Some(keys) = serai_latest.validator_sets().keys(set).await.unwrap() { @@ -65,8 +65,7 @@ pub async fn provide_batch(serai: &Serai, batch: Batch) -> [u8; 32] { #[allow(dead_code)] pub async fn mint_coin( serai: &Serai, - balance: Balance, - network: NetworkId, + balance: ExternalBalance, batch_id: u32, address: SeraiAddress, ) -> [u8; 32] { @@ -74,7 +73,7 @@ pub async fn mint_coin( OsRng.fill_bytes(&mut block_hash.0); let batch = Batch { - network, + network: balance.coin.network(), id: batch_id, block: block_hash, instructions: vec![InInstructionWithBalance { diff --git a/substrate/client/tests/common/validator_sets.rs b/substrate/client/tests/common/validator_sets.rs index 3238501a3..20f7e9513 100644 --- a/substrate/client/tests/common/validator_sets.rs +++ b/substrate/client/tests/common/validator_sets.rs @@ -15,7 +15,7 @@ use schnorrkel::Schnorrkel; use serai_client::{ validator_sets::{ - primitives::{ValidatorSet, KeyPair, musig_context, set_keys_message}, + primitives::{ExternalValidatorSet, KeyPair, musig_context, set_keys_message}, ValidatorSetsEvent, }, Amount, Serai, SeraiValidatorSets, @@ -26,7 +26,7 @@ use crate::common::tx::publish_tx; #[allow(dead_code)] pub async fn set_keys( serai: &Serai, - set: ValidatorSet, + set: ExternalValidatorSet, key_pair: KeyPair, pairs: &[Pair], ) -> [u8; 32] { @@ -46,7 +46,8 @@ pub async fn set_keys( assert_eq!(Ristretto::generator() * secret_key, pub_keys[i]); threshold_keys.push( - musig::(&musig_context(set), &Zeroizing::new(secret_key), &pub_keys).unwrap(), + musig::(&musig_context(set.into()), &Zeroizing::new(secret_key), &pub_keys) + .unwrap(), ); } diff --git a/substrate/client/tests/dex.rs b/substrate/client/tests/dex.rs index d02d52602..f41eef6be 100644 --- a/substrate/client/tests/dex.rs +++ b/substrate/client/tests/dex.rs @@ -6,8 +6,8 @@ use serai_abi::in_instructions::primitives::DexCall; use serai_client::{ primitives::{ - Amount, NetworkId, Coin, Balance, BlockHash, insecure_pair_from_name, ExternalAddress, - SeraiAddress, + Amount, Coin, Balance, BlockHash, insecure_pair_from_name, ExternalAddress, SeraiAddress, + ExternalCoin, ExternalBalance, }, in_instructions::primitives::{ InInstruction, InInstructionWithBalance, Batch, IN_INSTRUCTION_EXECUTOR, OutAddress, @@ -28,15 +28,14 @@ use common::{ // TODO: Check Transfer events serai_test!( add_liquidity: (|serai: Serai| async move { - let coin = Coin::Monero; + let coin = ExternalCoin::Monero; let pair = insecure_pair_from_name("Ferdie"); // mint sriXMR in the account so that we can add liq. // Ferdie account is already pre-funded with SRI. mint_coin( &serai, - Balance { coin, amount: Amount(100_000_000_000_000) }, - NetworkId::Monero, + ExternalBalance { coin, amount: Amount(100_000_000_000_000) }, 0, pair.clone().public().into(), ) @@ -61,7 +60,7 @@ serai_test!( vec![DexEvent::LiquidityAdded { who: pair.public().into(), mint_to: pair.public().into(), - pool_id: Coin::Monero, + pool_id: coin, coin_amount: coin_amount.0, sri_amount: sri_amount.0, lp_token_minted: 49_999999990000 @@ -71,15 +70,14 @@ serai_test!( // Tests coin -> SRI and SRI -> coin swaps. swap_coin_to_sri: (|serai: Serai| async move { - let coin = Coin::Ether; + let coin = ExternalCoin::Ether; let pair = insecure_pair_from_name("Ferdie"); // mint sriXMR in the account so that we can add liq. // Ferdie account is already pre-funded with SRI. mint_coin( &serai, - Balance { coin, amount: Amount(100_000_000_000_000) }, - NetworkId::Ethereum, + ExternalBalance { coin, amount: Amount(100_000_000_000_000) }, 0, pair.clone().public().into(), ) @@ -96,14 +94,21 @@ serai_test!( // now that we have our liquid pool, swap some coin to SRI. let mut amount_in = Amount(25_000_000_000_000); - let mut block = common_swap(&serai, coin, Coin::Serai, amount_in, Amount(1), 1, pair.clone()) + let mut block = common_swap( + &serai, + coin.into(), + Coin::Serai, + amount_in, + Amount(1), + 1, + pair.clone()) .await; // get only the swap events let mut events = serai.as_of(block).dex().events().await.unwrap(); events.retain(|e| matches!(e, DexEvent::SwapExecuted { .. })); - let mut path = BoundedVec::try_from(vec![coin, Coin::Serai]).unwrap(); + let mut path = BoundedVec::try_from(vec![coin.into(), Coin::Serai]).unwrap(); assert_eq!( events, vec![DexEvent::SwapExecuted { @@ -117,13 +122,21 @@ serai_test!( // now swap some SRI to coin amount_in = Amount(10_000_000_000_000); - block = common_swap(&serai, Coin::Serai, coin, amount_in, Amount(1), 2, pair.clone()).await; + block = common_swap( + &serai, + Coin::Serai, + coin.into(), + amount_in, + Amount(1), + 2, + pair.clone() + ).await; // get only the swap events let mut events = serai.as_of(block).dex().events().await.unwrap(); events.retain(|e| matches!(e, DexEvent::SwapExecuted { .. })); - path = BoundedVec::try_from(vec![Coin::Serai, coin]).unwrap(); + path = BoundedVec::try_from(vec![Coin::Serai, coin.into()]).unwrap(); assert_eq!( events, vec![DexEvent::SwapExecuted { @@ -137,23 +150,21 @@ serai_test!( }) swap_coin_to_coin: (|serai: Serai| async move { - let coin1 = Coin::Monero; - let coin2 = Coin::Dai; + let coin1 = ExternalCoin::Monero; + let coin2 = ExternalCoin::Dai; let pair = insecure_pair_from_name("Ferdie"); // mint coins mint_coin( &serai, - Balance { coin: coin1, amount: Amount(100_000_000_000_000) }, - NetworkId::Monero, + ExternalBalance { coin: coin1, amount: Amount(100_000_000_000_000) }, 0, pair.clone().public().into(), ) .await; mint_coin( &serai, - Balance { coin: coin2, amount: Amount(100_000_000_000_000) }, - NetworkId::Ethereum, + ExternalBalance { coin: coin2, amount: Amount(100_000_000_000_000) }, 0, pair.clone().public().into(), ) @@ -177,13 +188,21 @@ serai_test!( // swap coin1 -> coin2 let amount_in = Amount(25_000_000_000_000); - let block = common_swap(&serai, coin1, coin2, amount_in, Amount(1), 2, pair.clone()).await; + let block = common_swap( + &serai, + coin1.into(), + coin2.into(), + amount_in, + Amount(1), + 2, + pair.clone() + ).await; // get only the swap events let mut events = serai.as_of(block).dex().events().await.unwrap(); events.retain(|e| matches!(e, DexEvent::SwapExecuted { .. })); - let path = BoundedVec::try_from(vec![coin1, Coin::Serai, coin2]).unwrap(); + let path = BoundedVec::try_from(vec![coin1.into(), Coin::Serai, coin2.into()]).unwrap(); assert_eq!( events, vec![DexEvent::SwapExecuted { @@ -197,7 +216,7 @@ serai_test!( }) add_liquidity_in_instructions: (|serai: Serai| async move { - let coin = Coin::Bitcoin; + let coin = ExternalCoin::Bitcoin; let pair = insecure_pair_from_name("Ferdie"); let mut batch_id = 0; @@ -205,8 +224,7 @@ serai_test!( // Ferdie account is already pre-funded with SRI. mint_coin( &serai, - Balance { coin, amount: Amount(100_000_000_000_000) }, - NetworkId::Bitcoin, + ExternalBalance { coin, amount: Amount(100_000_000_000_000) }, batch_id, pair.clone().public().into(), ) @@ -227,12 +245,12 @@ serai_test!( let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); let batch = Batch { - network: NetworkId::Bitcoin, + network: coin.network(), id: batch_id, block: block_hash, instructions: vec![InInstructionWithBalance { instruction: InInstruction::Dex(DexCall::SwapAndAddLiquidity(pair.public().into())), - balance: Balance { coin: Coin::Bitcoin, amount: Amount(20_000_000_000_000) }, + balance: ExternalBalance { coin, amount: Amount(20_000_000_000_000) }, }], }; @@ -244,7 +262,7 @@ serai_test!( vec![DexEvent::LiquidityAdded { who: IN_INSTRUCTION_EXECUTOR, mint_to: pair.public().into(), - pool_id: Coin::Bitcoin, + pool_id: coin, coin_amount: 10_000_000_000_000, // half of sent amount sri_amount: 111_333_778_668, lp_token_minted: 1_054_092_553_383 @@ -253,8 +271,8 @@ serai_test!( }) swap_in_instructions: (|serai: Serai| async move { - let coin1 = Coin::Monero; - let coin2 = Coin::Ether; + let coin1 = ExternalCoin::Monero; + let coin2 = ExternalCoin::Ether; let pair = insecure_pair_from_name("Ferdie"); let mut coin1_batch_id = 0; let mut coin2_batch_id = 0; @@ -262,8 +280,7 @@ serai_test!( // mint coins mint_coin( &serai, - Balance { coin: coin1, amount: Amount(10_000_000_000_000_000) }, - NetworkId::Monero, + ExternalBalance { coin: coin1, amount: Amount(10_000_000_000_000_000) }, coin1_batch_id, pair.clone().public().into(), ) @@ -271,8 +288,7 @@ serai_test!( coin1_batch_id += 1; mint_coin( &serai, - Balance { coin: coin2, amount: Amount(100_000_000_000_000) }, - NetworkId::Ethereum, + ExternalBalance { coin: coin2, amount: Amount(100_000_000_000_000) }, coin2_batch_id, pair.clone().public().into(), ) @@ -305,18 +321,18 @@ serai_test!( let out_address = OutAddress::External(ExternalAddress::new(rand_bytes.clone()).unwrap()); // amount is the min out amount - let out_balance = Balance { coin: coin2, amount: Amount(1) }; + let out_balance = Balance { coin: coin2.into(), amount: Amount(1) }; // now that we have our pools, we can try to swap let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); let batch = Batch { - network: NetworkId::Monero, + network: coin1.network(), id: coin1_batch_id, block: block_hash, instructions: vec![InInstructionWithBalance { instruction: InInstruction::Dex(DexCall::Swap(out_balance, out_address)), - balance: Balance { coin: coin1, amount: Amount(200_000_000_000_000) }, + balance: ExternalBalance { coin: coin1, amount: Amount(200_000_000_000_000) }, }], }; @@ -325,7 +341,7 @@ serai_test!( let mut events = serai.as_of(block).dex().events().await.unwrap(); events.retain(|e| matches!(e, DexEvent::SwapExecuted { .. })); - let path = BoundedVec::try_from(vec![coin1, Coin::Serai, coin2]).unwrap(); + let path = BoundedVec::try_from(vec![coin1.into(), Coin::Serai, coin2.into()]).unwrap(); assert_eq!( events, vec![DexEvent::SwapExecuted { @@ -345,18 +361,18 @@ serai_test!( OutAddress::Serai(SeraiAddress::new(rand_bytes.clone().try_into().unwrap())); // amount is the min out amount - let out_balance = Balance { coin: coin1, amount: Amount(1) }; + let out_balance = Balance { coin: coin1.into(), amount: Amount(1) }; // now that we have our pools, we can try to swap let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); let batch = Batch { - network: NetworkId::Ethereum, + network: coin2.network(), id: coin2_batch_id, block: block_hash, instructions: vec![InInstructionWithBalance { instruction: InInstruction::Dex(DexCall::Swap(out_balance, out_address.clone())), - balance: Balance { coin: coin2, amount: Amount(200_000_000_000) }, + balance: ExternalBalance { coin: coin2, amount: Amount(200_000_000_000) }, }], }; @@ -364,7 +380,7 @@ serai_test!( let mut events = serai.as_of(block).dex().events().await.unwrap(); events.retain(|e| matches!(e, DexEvent::SwapExecuted { .. })); - let path = BoundedVec::try_from(vec![coin2, Coin::Serai, coin1]).unwrap(); + let path = BoundedVec::try_from(vec![coin2.into(), Coin::Serai, coin1.into()]).unwrap(); assert_eq!( events, vec![DexEvent::SwapExecuted { @@ -389,12 +405,12 @@ serai_test!( let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); let batch = Batch { - network: NetworkId::Monero, + network: coin1.network(), id: coin1_batch_id, block: block_hash, instructions: vec![InInstructionWithBalance { instruction: InInstruction::Dex(DexCall::Swap(out_balance, out_address.clone())), - balance: Balance { coin: coin1, amount: Amount(100_000_000_000_000) }, + balance: ExternalBalance { coin: coin1, amount: Amount(100_000_000_000_000) }, }], }; @@ -402,7 +418,7 @@ serai_test!( let mut events = serai.as_of(block).dex().events().await.unwrap(); events.retain(|e| matches!(e, DexEvent::SwapExecuted { .. })); - let path = BoundedVec::try_from(vec![coin1, Coin::Serai]).unwrap(); + let path = BoundedVec::try_from(vec![coin1.into(), Coin::Serai]).unwrap(); assert_eq!( events, vec![DexEvent::SwapExecuted { diff --git a/substrate/client/tests/dht.rs b/substrate/client/tests/dht.rs index 82450e461..0d27c91e5 100644 --- a/substrate/client/tests/dht.rs +++ b/substrate/client/tests/dht.rs @@ -1,4 +1,4 @@ -use serai_client::{primitives::NetworkId, Serai}; +use serai_client::{primitives::ExternalNetworkId, Serai}; #[tokio::test] async fn dht() { @@ -44,7 +44,7 @@ async fn dht() { assert!(!Serai::new(serai_rpc.clone()) .await .unwrap() - .p2p_validators(NetworkId::Bitcoin) + .p2p_validators(ExternalNetworkId::Bitcoin.into()) .await .unwrap() .is_empty()); diff --git a/substrate/client/tests/emissions.rs b/substrate/client/tests/emissions.rs index f510d4862..3e2b46f23 100644 --- a/substrate/client/tests/emissions.rs +++ b/substrate/client/tests/emissions.rs @@ -7,16 +7,13 @@ use serai_abi::{ emissions::primitives::{INITIAL_REWARD_PER_BLOCK, SECURE_BY}, in_instructions::primitives::Batch, primitives::{ - BlockHash, Coin, COINS, FAST_EPOCH_DURATION, FAST_EPOCH_INITIAL_PERIOD, NETWORKS, - TARGET_BLOCK_TIME, + BlockHash, ExternalBalance, ExternalCoin, ExternalNetworkId, EXTERNAL_NETWORKS, + FAST_EPOCH_DURATION, FAST_EPOCH_INITIAL_PERIOD, NETWORKS, TARGET_BLOCK_TIME, Amount, NetworkId, }, validator_sets::primitives::Session, }; -use serai_client::{ - primitives::{Amount, NetworkId, Balance}, - Serai, -}; +use serai_client::Serai; mod common; use common::{genesis_liquidity::set_up_genesis, in_instructions::provide_batch}; @@ -27,31 +24,32 @@ serai_test_fast_epoch!( }) ); -async fn send_batches(serai: &Serai, ids: &mut HashMap) { - for network in NETWORKS { - if network != NetworkId::Serai { - // set up batch id - ids - .entry(network) - .and_modify(|v| { - *v += 1; - }) - .or_insert(0); - - // set up block hash - let mut block = BlockHash([0; 32]); - OsRng.fill_bytes(&mut block.0); - - provide_batch(serai, Batch { network, id: ids[&network], block, instructions: vec![] }).await; - } +async fn send_batches(serai: &Serai, ids: &mut HashMap) { + for network in EXTERNAL_NETWORKS { + // set up batch id + ids + .entry(network) + .and_modify(|v| { + *v += 1; + }) + .or_insert(0); + + // set up block hash + let mut block = BlockHash([0; 32]); + OsRng.fill_bytes(&mut block.0); + + provide_batch(serai, Batch { network, id: ids[&network], block, instructions: vec![] }).await; } } async fn test_emissions(serai: Serai) { // set up the genesis - let coins = COINS.into_iter().filter(|c| *c != Coin::native()).collect::>(); - let values = HashMap::from([(Coin::Monero, 184100), (Coin::Ether, 4785000), (Coin::Dai, 1500)]); - let (_, mut batch_ids) = set_up_genesis(&serai, &coins, &values).await; + let values = HashMap::from([ + (ExternalCoin::Monero, 184100), + (ExternalCoin::Ether, 4785000), + (ExternalCoin::Dai, 1500), + ]); + let (_, mut batch_ids) = set_up_genesis(&serai, &values).await; // wait until genesis is complete let mut genesis_complete_block = None; @@ -144,7 +142,7 @@ async fn test_emissions(serai: Serai) { } /// Returns the required stake in terms SRI for a given `Balance`. -async fn required_stake(serai: &TemporalSerai<'_>, balance: Balance) -> u64 { +async fn required_stake(serai: &TemporalSerai<'_>, balance: ExternalBalance) -> u64 { // This is inclusive to an increase in accuracy let sri_per_coin = serai.dex().oracle_value(balance.coin).await.unwrap().unwrap_or(Amount(0)); @@ -208,18 +206,14 @@ async fn get_distances( // we can check the supply to see how much coin hence liability we have. let mut distances: HashMap = HashMap::new(); let mut total_distance = 0; - for n in NETWORKS { - if n == NetworkId::Serai { - continue; - } - + for n in EXTERNAL_NETWORKS { let mut required = 0; for c in n.coins() { - let amount = serai.coins().coin_supply(*c).await.unwrap(); - required += required_stake(serai, Balance { coin: *c, amount }).await; + let amount = serai.coins().coin_supply(c.into()).await.unwrap(); + required += required_stake(serai, ExternalBalance { coin: c, amount }).await; } - let mut current = *current_stake.get(&n).unwrap(); + let mut current = *current_stake.get(&n.into()).unwrap(); if current > required { current = required; } @@ -227,7 +221,7 @@ async fn get_distances( let distance = required - current; total_distance += distance; - distances.insert(n, distance); + distances.insert(n.into(), distance); } // add serai network portion(20%) diff --git a/substrate/client/tests/genesis_liquidity.rs b/substrate/client/tests/genesis_liquidity.rs index 8b2b8d8f9..e2a593cf1 100644 --- a/substrate/client/tests/genesis_liquidity.rs +++ b/substrate/client/tests/genesis_liquidity.rs @@ -2,7 +2,7 @@ use std::{time::Duration, collections::HashMap}; use serai_client::Serai; -use serai_abi::primitives::{Coin, COINS, Amount, GENESIS_SRI}; +use serai_abi::primitives::{Amount, Coin, ExternalCoin, COINS, EXTERNAL_COINS, GENESIS_SRI}; use serai_client::genesis_liquidity::primitives::{ GENESIS_LIQUIDITY_ACCOUNT, INITIAL_GENESIS_LP_SHARES, @@ -19,9 +19,12 @@ serai_test_fast_epoch!( pub async fn test_genesis_liquidity(serai: Serai) { // set up the genesis - let coins = COINS.into_iter().filter(|c| *c != Coin::native()).collect::>(); - let values = HashMap::from([(Coin::Monero, 184100), (Coin::Ether, 4785000), (Coin::Dai, 1500)]); - let (accounts, _) = set_up_genesis(&serai, &coins, &values).await; + let values = HashMap::from([ + (ExternalCoin::Monero, 184100), + (ExternalCoin::Ether, 4785000), + (ExternalCoin::Dai, 1500), + ]); + let (accounts, _) = set_up_genesis(&serai, &values).await; // wait until genesis is complete while serai @@ -55,9 +58,9 @@ pub async fn test_genesis_liquidity(serai: Serai) { // check pools has proper liquidity let mut pool_amounts = HashMap::new(); let mut total_value = 0u128; - for coin in coins.clone() { + for coin in EXTERNAL_COINS { let total_coin = accounts[&coin].iter().fold(0u128, |acc, value| acc + u128::from(value.1 .0)); - let value = if coin != Coin::Bitcoin { + let value = if coin != ExternalCoin::Bitcoin { (total_coin * u128::from(values[&coin])) / 10u128.pow(coin.decimals()) } else { total_coin @@ -69,8 +72,8 @@ pub async fn test_genesis_liquidity(serai: Serai) { // check distributed SRI per pool let mut total_sri_distributed = 0u128; - for coin in coins.clone() { - let sri = if coin == *COINS.last().unwrap() { + for coin in EXTERNAL_COINS { + let sri = if coin == *EXTERNAL_COINS.last().unwrap() { u128::from(GENESIS_SRI).checked_sub(total_sri_distributed).unwrap() } else { (pool_amounts[&coin].1 * u128::from(GENESIS_SRI)) / total_value @@ -83,7 +86,7 @@ pub async fn test_genesis_liquidity(serai: Serai) { } // check each liquidity provider got liquidity tokens proportional to their value - for coin in coins { + for coin in EXTERNAL_COINS { let liq_supply = serai.genesis_liquidity().supply(coin).await.unwrap(); for (acc, amount) in &accounts[&coin] { let acc_liq_shares = serai.genesis_liquidity().liquidity(acc, coin).await.unwrap().shares; diff --git a/substrate/client/tests/validator_sets.rs b/substrate/client/tests/validator_sets.rs index c2c6c509d..dee2bb42b 100644 --- a/substrate/client/tests/validator_sets.rs +++ b/substrate/client/tests/validator_sets.rs @@ -7,17 +7,18 @@ use sp_core::{ use serai_client::{ primitives::{ - NETWORKS, NetworkId, BlockHash, insecure_pair_from_name, FAST_EPOCH_DURATION, TARGET_BLOCK_TIME, + NETWORKS, NetworkId, BlockHash, insecure_pair_from_name, FAST_EPOCH_DURATION, + TARGET_BLOCK_TIME, ExternalNetworkId, Amount, }, validator_sets::{ - primitives::{Session, ValidatorSet, KeyPair}, + primitives::{Session, ValidatorSet, ExternalValidatorSet, KeyPair}, ValidatorSetsEvent, }, in_instructions::{ primitives::{Batch, SignedBatch, batch_message}, SeraiInInstructions, }, - Amount, Serai, + Serai, }; mod common; @@ -58,8 +59,8 @@ async fn get_ordered_keys(serai: &Serai, network: NetworkId, accounts: &[Pair]) serai_test!( set_keys_test: (|serai: Serai| async move { - let network = NetworkId::Bitcoin; - let set = ValidatorSet { session: Session(0), network }; + let network = ExternalNetworkId::Bitcoin; + let set = ExternalValidatorSet { session: Session(0), network }; let pair = insecure_pair_from_name("Alice"); let public = pair.public(); @@ -89,7 +90,7 @@ serai_test!( { let vs_serai = serai.as_of_latest_finalized_block().await.unwrap(); let vs_serai = vs_serai.validator_sets(); - let participants = vs_serai.participants(set.network).await + let participants = vs_serai.participants(set.network.into()).await .unwrap() .unwrap() .into_iter() @@ -197,9 +198,9 @@ async fn validator_set_rotation() { // amounts for single key share per network let key_shares = HashMap::from([ (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), - (NetworkId::Bitcoin, Amount(1_000_000 * 10_u64.pow(8))), - (NetworkId::Monero, Amount(100_000 * 10_u64.pow(8))), - (NetworkId::Ethereum, Amount(1_000_000 * 10_u64.pow(8))), + (NetworkId::External(ExternalNetworkId::Bitcoin), Amount(1_000_000 * 10_u64.pow(8))), + (NetworkId::External(ExternalNetworkId::Monero), Amount(100_000 * 10_u64.pow(8))), + (NetworkId::External(ExternalNetworkId::Ethereum), Amount(1_000_000 * 10_u64.pow(8))), ]); // genesis participants per network @@ -208,9 +209,9 @@ async fn validator_set_rotation() { accounts[.. 4].to_vec().iter().map(|pair| pair.public()).collect::>(); let mut participants = HashMap::from([ (NetworkId::Serai, default_participants.clone()), - (NetworkId::Bitcoin, default_participants.clone()), - (NetworkId::Monero, default_participants.clone()), - (NetworkId::Ethereum, default_participants), + (NetworkId::External(ExternalNetworkId::Bitcoin), default_participants.clone()), + (NetworkId::External(ExternalNetworkId::Monero), default_participants.clone()), + (NetworkId::External(ExternalNetworkId::Ethereum), default_participants), ]); // test the set rotation @@ -237,7 +238,8 @@ async fn validator_set_rotation() { // set the keys if it is an external set if network != NetworkId::Serai { - let set = ValidatorSet { session: Session(0), network }; + let set = + ExternalValidatorSet { session: Session(0), network: network.try_into().unwrap() }; let key_pair = get_random_key_pair(); let pairs = get_ordered_keys(&serai, network, &accounts).await; set_keys(&serai, set, key_pair, &pairs).await; @@ -265,7 +267,8 @@ async fn validator_set_rotation() { if network != NetworkId::Serai { // set the keys if it is an external set - let set = ValidatorSet { session: Session(1), network }; + let set = + ExternalValidatorSet { session: Session(1), network: network.try_into().unwrap() }; // we need the whole substrate key pair to sign the batch let (substrate_pair, key_pair) = { @@ -283,7 +286,12 @@ async fn validator_set_rotation() { // provide a batch to complete the handover and retire the previous set let mut block_hash = BlockHash([0; 32]); OsRng.fill_bytes(&mut block_hash.0); - let batch = Batch { network, id: 0, block: block_hash, instructions: vec![] }; + let batch = Batch { + network: network.try_into().unwrap(), + id: 0, + block: block_hash, + instructions: vec![], + }; publish_tx( &serai, &SeraiInInstructions::execute_batch(SignedBatch { diff --git a/substrate/coins/pallet/src/lib.rs b/substrate/coins/pallet/src/lib.rs index a633ed070..dd64b2b6b 100644 --- a/substrate/coins/pallet/src/lib.rs +++ b/substrate/coins/pallet/src/lib.rs @@ -1,13 +1,13 @@ #![cfg_attr(not(feature = "std"), no_std)] -use serai_primitives::{Coin, SubstrateAmount, Balance}; +use serai_primitives::{Balance, Coin, ExternalBalance, SubstrateAmount}; pub trait AllowMint { - fn is_allowed(balance: &Balance) -> bool; + fn is_allowed(balance: &ExternalBalance) -> bool; } impl AllowMint for () { - fn is_allowed(_: &Balance) -> bool { + fn is_allowed(_: &ExternalBalance) -> bool { true } } @@ -161,7 +161,10 @@ pub mod pallet { pub fn mint(to: Public, balance: Balance) -> Result<(), Error> { // If the coin isn't Serai, which we're always allowed to mint, and the mint isn't explicitly // allowed, error - if (balance.coin != Coin::Serai) && (!T::AllowMint::is_allowed(&balance)) { + if !ExternalCoin::try_from(balance.coin) + .map(|coin| T::AllowMint::is_allowed(&ExternalBalance { coin, amount: balance.amount })) + .unwrap_or(true) + { Err(Error::::MintNotAllowed)?; } @@ -230,22 +233,18 @@ pub mod pallet { } /// Burn `balance` with `OutInstructionWithBalance` from the caller. - /// Errors if called for SRI or Instance1 instance of this pallet. #[pallet::call_index(2)] #[pallet::weight((0, DispatchClass::Normal))] // TODO pub fn burn_with_instruction( origin: OriginFor, instruction: OutInstructionWithBalance, ) -> DispatchResult { - if instruction.balance.coin == Coin::Serai { - Err(Error::::BurnWithInstructionNotAllowed)?; - } if TypeId::of::() == TypeId::of::() { Err(Error::::BurnWithInstructionNotAllowed)?; } let from = ensure_signed(origin)?; - Self::burn_internal(from, instruction.balance)?; + Self::burn_internal(from, instruction.balance.into())?; Self::deposit_event(Event::BurnWithInstruction { from, instruction }); Ok(()) } diff --git a/substrate/coins/primitives/src/lib.rs b/substrate/coins/primitives/src/lib.rs index a7b45cf0c..5aca029a2 100644 --- a/substrate/coins/primitives/src/lib.rs +++ b/substrate/coins/primitives/src/lib.rs @@ -13,7 +13,7 @@ use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; -use serai_primitives::{Balance, SeraiAddress, ExternalAddress, Data, system_address}; +use serai_primitives::{system_address, Data, ExternalAddress, ExternalBalance, SeraiAddress}; pub const FEE_ACCOUNT: SeraiAddress = system_address(b"Coins-fees"); @@ -32,7 +32,7 @@ pub struct OutInstruction { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct OutInstructionWithBalance { pub instruction: OutInstruction, - pub balance: Balance, + pub balance: ExternalBalance, } #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] diff --git a/substrate/dex/pallet/src/benchmarking.rs b/substrate/dex/pallet/src/benchmarking.rs index fb23b12a4..071411d73 100644 --- a/substrate/dex/pallet/src/benchmarking.rs +++ b/substrate/dex/pallet/src/benchmarking.rs @@ -38,7 +38,7 @@ type AccountIdLookupOf = <::Lookup as StaticLookup type LiquidityTokens = coins_pallet::Pallet; -fn create_coin(coin: &Coin) -> (T::AccountId, AccountIdLookupOf) { +fn create_coin(coin: &ExternalCoin) -> (T::AccountId, AccountIdLookupOf) { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller); assert_ok!(Coins::::mint( @@ -47,12 +47,14 @@ fn create_coin(coin: &Coin) -> (T::AccountId, AccountIdLookupOf) { )); assert_ok!(Coins::::mint( caller, - Balance { coin: *coin, amount: Amount(INITIAL_COIN_BALANCE) } + Balance { coin: (*coin).into(), amount: Amount(INITIAL_COIN_BALANCE) } )); (caller, caller_lookup) } -fn create_coin_and_pool(coin: &Coin) -> (Coin, T::AccountId, AccountIdLookupOf) { +fn create_coin_and_pool( + coin: &ExternalCoin, +) -> (ExternalCoin, T::AccountId, AccountIdLookupOf) { let (caller, caller_lookup) = create_coin::(coin); assert_ok!(Dex::::create_pool(*coin)); @@ -62,7 +64,7 @@ fn create_coin_and_pool(coin: &Coin) -> (Coin, T::AccountId, AccountI benchmarks! { add_liquidity { let coin1 = Coin::native(); - let coin2 = Coin::Bitcoin; + let coin2 = ExternalCoin::Bitcoin; let (lp_token, caller, _) = create_coin_and_pool::(&coin2); let add_amount: u64 = 1000; }: _( @@ -75,13 +77,13 @@ benchmarks! { caller ) verify { - let pool_id = Dex::::get_pool_id(coin1, coin2).unwrap(); + let pool_id = Dex::::get_pool_id(coin1, coin2.into()).unwrap(); let lp_minted = Dex::::calc_lp_amount_for_zero_supply( add_amount, 1000u64, ).unwrap(); assert_eq!( - LiquidityTokens::::balance(caller, lp_token).0, + LiquidityTokens::::balance(caller, lp_token.into()).0, lp_minted ); assert_eq!( @@ -91,7 +93,7 @@ benchmarks! { assert_eq!( Coins::::balance( Dex::::get_pool_account(pool_id), - Coin::Bitcoin, + ExternalCoin::Bitcoin.into(), ).0, 1000 ); @@ -99,7 +101,7 @@ benchmarks! { remove_liquidity { let coin1 = Coin::native(); - let coin2 = Coin::Monero; + let coin2 = ExternalCoin::Monero; let (lp_token, caller, _) = create_coin_and_pool::(&coin2); let add_amount: u64 = 100; let lp_minted = Dex::::calc_lp_amount_for_zero_supply( @@ -117,7 +119,7 @@ benchmarks! { 0u64, caller, )?; - let total_supply = LiquidityTokens::::supply(lp_token); + let total_supply = LiquidityTokens::::supply(Coin::from(lp_token)); }: _( SystemOrigin::Signed(caller), coin2, @@ -127,7 +129,7 @@ benchmarks! { caller ) verify { - let new_total_supply = LiquidityTokens::::supply(lp_token); + let new_total_supply = LiquidityTokens::::supply(Coin::from(lp_token)); assert_eq!( new_total_supply, total_supply - remove_lp_amount @@ -136,8 +138,8 @@ benchmarks! { swap_exact_tokens_for_tokens { let native = Coin::native(); - let coin1 = Coin::Bitcoin; - let coin2 = Coin::Ether; + let coin1 = ExternalCoin::Bitcoin; + let coin2 = ExternalCoin::Ether; let (_, caller, _) = create_coin_and_pool::(&coin1); let (_, _) = create_coin::(&coin2); @@ -168,21 +170,21 @@ benchmarks! { caller, )?; - let path = vec![coin1, native, coin2]; + let path = vec![Coin::from(coin1), native, Coin::from(coin2)]; let path = BoundedVec::<_, T::MaxSwapPathLength>::try_from(path).unwrap(); let native_balance = Coins::::balance(caller, native).0; - let coin1_balance = Coins::::balance(caller, Coin::Bitcoin).0; + let coin1_balance = Coins::::balance(caller, ExternalCoin::Bitcoin.into()).0; }: _(SystemOrigin::Signed(caller), path, swap_amount, 1u64, caller) verify { let ed_bump = 2u64; - let new_coin1_balance = Coins::::balance(caller, Coin::Bitcoin).0; + let new_coin1_balance = Coins::::balance(caller, ExternalCoin::Bitcoin.into()).0; assert_eq!(new_coin1_balance, coin1_balance - 100u64); } swap_tokens_for_exact_tokens { let native = Coin::native(); - let coin1 = Coin::Bitcoin; - let coin2 = Coin::Ether; + let coin1 = ExternalCoin::Bitcoin; + let coin2 = ExternalCoin::Ether; let (_, caller, _) = create_coin_and_pool::(&coin1); let (_, _) = create_coin::(&coin2); @@ -208,10 +210,10 @@ benchmarks! { 0u64, caller, )?; - let path = vec![coin1, native, coin2]; + let path = vec![Coin::from(coin1), native, Coin::from(coin2)]; let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); - let coin2_balance = Coins::::balance(caller, Coin::Ether).0; + let coin2_balance = Coins::::balance(caller, ExternalCoin::Ether.into()).0; }: _( SystemOrigin::Signed(caller), path.clone(), @@ -220,7 +222,7 @@ benchmarks! { caller ) verify { - let new_coin2_balance = Coins::::balance(caller, Coin::Ether).0; + let new_coin2_balance = Coins::::balance(caller, ExternalCoin::Ether.into()).0; assert_eq!(new_coin2_balance, coin2_balance + 100u64); } diff --git a/substrate/dex/pallet/src/lib.rs b/substrate/dex/pallet/src/lib.rs index 60a38926b..8da63a7be 100644 --- a/substrate/dex/pallet/src/lib.rs +++ b/substrate/dex/pallet/src/lib.rs @@ -78,7 +78,7 @@ mod tests; #[cfg(test)] mod mock; -use frame_support::ensure; +use frame_support::{ensure, pallet_prelude::*, BoundedBTreeSet}; use frame_system::{ pallet_prelude::{BlockNumberFor, OriginFor}, ensure_signed, @@ -86,9 +86,12 @@ use frame_system::{ pub use pallet::*; -use sp_runtime::{traits::TrailingZeroInput, DispatchError}; +use sp_runtime::{ + traits::{TrailingZeroInput, IntegerSquareRoot}, + DispatchError, +}; -use serai_primitives::{NetworkId, Coin, SubstrateAmount}; +use serai_primitives::*; use sp_std::prelude::*; pub use types::*; @@ -103,20 +106,16 @@ pub use weights::WeightInfo; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, BoundedBTreeSet}; use sp_core::sr25519::Public; - use sp_runtime::traits::IntegerSquareRoot; use coins_pallet::{Pallet as CoinsPallet, Config as CoinsConfig}; - use serai_primitives::{Coin, Amount, Balance, SubstrateAmount, reverse_lexicographic_order}; - /// Pool ID. /// /// The pool's `AccountId` is derived from this type. Any changes to the type may necessitate a /// migration. - pub type PoolId = Coin; + pub type PoolId = ExternalCoin; /// LiquidityTokens Pallet as an instance of coins pallet. pub type LiquidityTokens = coins_pallet::Pallet; @@ -164,7 +163,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn spot_price_for_block)] pub type SpotPriceForBlock = - StorageDoubleMap<_, Identity, BlockNumberFor, Identity, Coin, Amount, OptionQuery>; + StorageDoubleMap<_, Identity, BlockNumberFor, Identity, ExternalCoin, Amount, OptionQuery>; /// Moving window of prices from each block. /// @@ -173,30 +172,32 @@ pub mod pallet { /// low to high. #[pallet::storage] pub type SpotPrices = - StorageDoubleMap<_, Identity, Coin, Identity, [u8; 8], u16, OptionQuery>; + StorageDoubleMap<_, Identity, ExternalCoin, Identity, [u8; 8], u16, OptionQuery>; // SpotPrices, yet with keys stored in reverse lexicographic order. #[pallet::storage] pub type ReverseSpotPrices = - StorageDoubleMap<_, Identity, Coin, Identity, [u8; 8], (), OptionQuery>; + StorageDoubleMap<_, Identity, ExternalCoin, Identity, [u8; 8], (), OptionQuery>; /// Current length of the `SpotPrices` map. #[pallet::storage] - pub type SpotPricesLength = StorageMap<_, Identity, Coin, u16, OptionQuery>; + pub type SpotPricesLength = StorageMap<_, Identity, ExternalCoin, u16, OptionQuery>; /// Current position of the median within the `SpotPrices` map; #[pallet::storage] - pub type CurrentMedianPosition = StorageMap<_, Identity, Coin, u16, OptionQuery>; + pub type CurrentMedianPosition = + StorageMap<_, Identity, ExternalCoin, u16, OptionQuery>; /// Current median price of the prices in the `SpotPrices` map at any given time. #[pallet::storage] #[pallet::getter(fn median_price)] - pub type MedianPrice = StorageMap<_, Identity, Coin, Amount, OptionQuery>; + pub type MedianPrice = StorageMap<_, Identity, ExternalCoin, Amount, OptionQuery>; /// The price used for evaluating economic security, which is the highest observed median price. #[pallet::storage] #[pallet::getter(fn security_oracle_value)] - pub type SecurityOracleValue = StorageMap<_, Identity, Coin, Amount, OptionQuery>; + pub type SecurityOracleValue = + StorageMap<_, Identity, ExternalCoin, Amount, OptionQuery>; /// Total swap volume of a given pool in terms of SRI. #[pallet::storage] @@ -205,7 +206,7 @@ pub mod pallet { impl Pallet { fn restore_median( - coin: Coin, + coin: ExternalCoin, mut current_median_pos: u16, mut current_median: Amount, length: u16, @@ -256,7 +257,7 @@ pub mod pallet { MedianPrice::::set(coin, Some(current_median)); } - pub(crate) fn insert_into_median(coin: Coin, amount: Amount) { + pub(crate) fn insert_into_median(coin: ExternalCoin, amount: Amount) { let new_quantity_of_presences = SpotPrices::::get(coin, amount.0.to_be_bytes()).unwrap_or(0) + 1; SpotPrices::::set(coin, amount.0.to_be_bytes(), Some(new_quantity_of_presences)); @@ -286,7 +287,7 @@ pub mod pallet { Self::restore_median(coin, current_median_pos, current_median, new_length); } - pub(crate) fn remove_from_median(coin: Coin, amount: Amount) { + pub(crate) fn remove_from_median(coin: ExternalCoin, amount: Amount) { let mut current_median = MedianPrice::::get(coin).unwrap(); let mut current_median_pos = CurrentMedianPosition::::get(coin).unwrap(); @@ -451,7 +452,7 @@ pub mod pallet { // insert the new price to our oracle window // The spot price for 1 coin, in atomic units, to SRI is used let sri_per_coin = - if let Ok((sri_balance, coin_balance)) = Self::get_reserves(&Coin::native(), &coin) { + if let Ok((sri_balance, coin_balance)) = Self::get_reserves(&Coin::Serai, &coin.into()) { // We use 1 coin to handle rounding errors which may occur with atomic units // If we used atomic units, any coin whose atomic unit is worth less than SRI's atomic // unit would cause a 'price' of 0 @@ -493,9 +494,9 @@ pub mod pallet { /// (the id of which is returned in the `Event::PoolCreated` event). /// /// Once a pool is created, someone may [`Pallet::add_liquidity`] to it. - pub(crate) fn create_pool(coin: Coin) -> DispatchResult { + pub(crate) fn create_pool(coin: ExternalCoin) -> DispatchResult { // get pool_id - let pool_id = Self::get_pool_id(coin, Coin::Serai)?; + let pool_id = Self::get_pool_id(coin.into(), Coin::native())?; ensure!(!Pools::::contains_key(pool_id), Error::::PoolExists); let pool_account = Self::get_pool_account(pool_id); @@ -508,9 +509,11 @@ pub mod pallet { /// A hook to be called whenever a network's session is rotated. pub fn on_new_session(network: NetworkId) { - // reset the oracle value - for coin in network.coins() { - SecurityOracleValue::::set(*coin, Self::median_price(coin)); + // Only track the price for non-SRI coins as this is SRI denominated + if let NetworkId::External(n) = network { + for coin in n.coins() { + SecurityOracleValue::::set(coin, Self::median_price(coin)); + } } } } @@ -532,7 +535,7 @@ pub mod pallet { #[allow(clippy::too_many_arguments)] pub fn add_liquidity( origin: OriginFor, - coin: Coin, + coin: ExternalCoin, coin_desired: SubstrateAmount, sri_desired: SubstrateAmount, coin_min: SubstrateAmount, @@ -542,7 +545,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; ensure!((sri_desired > 0) && (coin_desired > 0), Error::::WrongDesiredAmount); - let pool_id = Self::get_pool_id(coin, Coin::Serai)?; + let pool_id = Self::get_pool_id(coin.into(), Coin::native())?; // create the pool if it doesn't exist. We can just attempt to do that because our checks // far enough to allow that. @@ -552,7 +555,7 @@ pub mod pallet { let pool_account = Self::get_pool_account(pool_id); let sri_reserve = Self::get_balance(&pool_account, Coin::Serai); - let coin_reserve = Self::get_balance(&pool_account, coin); + let coin_reserve = Self::get_balance(&pool_account, coin.into()); let sri_amount: SubstrateAmount; let coin_amount: SubstrateAmount; @@ -583,16 +586,20 @@ pub mod pallet { &pool_account, Balance { coin: Coin::Serai, amount: Amount(sri_amount) }, )?; - Self::transfer(&sender, &pool_account, Balance { coin, amount: Amount(coin_amount) })?; + Self::transfer( + &sender, + &pool_account, + Balance { coin: coin.into(), amount: Amount(coin_amount) }, + )?; - let total_supply = LiquidityTokens::::supply(coin); + let total_supply = LiquidityTokens::::supply(Coin::from(coin)); let lp_token_amount: SubstrateAmount; if total_supply == 0 { lp_token_amount = Self::calc_lp_amount_for_zero_supply(sri_amount, coin_amount)?; LiquidityTokens::::mint( pool_account, - Balance { coin, amount: Amount(T::MintMinLiquidity::get()) }, + Balance { coin: coin.into(), amount: Amount(T::MintMinLiquidity::get()) }, )?; } else { let side1 = Self::mul_div(sri_amount, total_supply, sri_reserve)?; @@ -605,7 +612,10 @@ pub mod pallet { Error::::InsufficientLiquidityMinted ); - LiquidityTokens::::mint(mint_to, Balance { coin, amount: Amount(lp_token_amount) })?; + LiquidityTokens::::mint( + mint_to, + Balance { coin: coin.into(), amount: Amount(lp_token_amount) }, + )?; Self::deposit_event(Event::LiquidityAdded { who: sender, @@ -626,25 +636,24 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_liquidity())] pub fn remove_liquidity( origin: OriginFor, - coin: Coin, + coin: ExternalCoin, lp_token_burn: SubstrateAmount, coin_min_receive: SubstrateAmount, sri_min_receive: SubstrateAmount, withdraw_to: T::AccountId, ) -> DispatchResult { let sender = ensure_signed(origin.clone())?; - ensure!(coin != Coin::Serai, Error::::EqualCoins); - let pool_id = Self::get_pool_id(coin, Coin::Serai).unwrap(); + let pool_id = Self::get_pool_id(coin.into(), Coin::native()).unwrap(); ensure!(lp_token_burn > 0, Error::::ZeroLiquidity); Pools::::get(pool_id).as_ref().ok_or(Error::::PoolNotFound)?; let pool_account = Self::get_pool_account(pool_id); let sri_reserve = Self::get_balance(&pool_account, Coin::Serai); - let coin_reserve = Self::get_balance(&pool_account, coin); + let coin_reserve = Self::get_balance(&pool_account, coin.into()); - let total_supply = LiquidityTokens::::supply(coin); + let total_supply = LiquidityTokens::::supply(Coin::from(coin)); let lp_redeem_amount = lp_token_burn; let sri_amount = Self::mul_div(lp_redeem_amount, sri_reserve, total_supply)?; @@ -665,14 +674,21 @@ pub mod pallet { ensure!(coin_reserve_left >= 1, Error::::ReserveLeftLessThanMinimum); // burn the provided lp token amount that includes the fee - LiquidityTokens::::burn(origin, Balance { coin, amount: Amount(lp_token_burn) })?; + LiquidityTokens::::burn( + origin, + Balance { coin: coin.into(), amount: Amount(lp_token_burn) }, + )?; Self::transfer( &pool_account, &withdraw_to, Balance { coin: Coin::Serai, amount: Amount(sri_amount) }, )?; - Self::transfer(&pool_account, &withdraw_to, Balance { coin, amount: Amount(coin_amount) })?; + Self::transfer( + &pool_account, + &withdraw_to, + Balance { coin: coin.into(), amount: Amount(coin_amount) }, + )?; Self::deposit_event(Event::LiquidityRemoved { who: sender, @@ -920,11 +936,9 @@ pub mod pallet { pub fn get_pool_id(coin1: Coin, coin2: Coin) -> Result> { ensure!((coin1 == Coin::Serai) || (coin2 == Coin::Serai), Error::::PoolNotFound); ensure!(coin1 != coin2, Error::::EqualCoins); - if coin1 == Coin::Serai { - Ok(coin2) - } else { - Ok(coin1) - } + ExternalCoin::try_from(coin1) + .or_else(|()| ExternalCoin::try_from(coin2)) + .map_err(|()| Error::::PoolNotFound) } /// Returns the balance of each coin in the pool. diff --git a/substrate/dex/pallet/src/tests.rs b/substrate/dex/pallet/src/tests.rs index ee714471f..8770b5174 100644 --- a/substrate/dex/pallet/src/tests.rs +++ b/substrate/dex/pallet/src/tests.rs @@ -18,7 +18,10 @@ // It has been forked into a crate distributed under the AGPL 3.0. // Please check the current distribution for up-to-date copyright and licensing information. -use crate::{mock::*, *}; +use crate::{ + mock::{*, MEDIAN_PRICE_WINDOW_LENGTH}, + *, +}; use frame_support::{assert_noop, assert_ok}; pub use coins_pallet as coins; @@ -72,11 +75,13 @@ fn check_pool_accounts_dont_collide() { let mut map = HashSet::new(); for coin in coins() { - let account = Dex::get_pool_account(coin); - if map.contains(&account) { - panic!("Collision at {coin:?}"); + if let Coin::External(c) = coin { + let account = Dex::get_pool_account(c); + if map.contains(&account) { + panic!("Collision at {c:?}"); + } + map.insert(account); } - map.insert(account); } } @@ -98,11 +103,11 @@ fn can_create_pool() { let coin_account_deposit: u64 = 0; let user: PublicKey = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Monero); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(1000) })); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_eq!(balance(user, coin1), 1000 - coin_account_deposit); @@ -111,15 +116,13 @@ fn can_create_pool() { [Event::::PoolCreated { pool_id, pool_account: Dex::get_pool_account(pool_id) }] ); assert_eq!(pools(), vec![pool_id]); - - assert_noop!(Dex::create_pool(coin1), Error::::EqualCoins); }); } #[test] fn create_same_pool_twice_should_fail() { new_test_ext().execute_with(|| { - let coin = Coin::Dai; + let coin = ExternalCoin::Dai; assert_ok!(Dex::create_pool(coin)); assert_noop!(Dex::create_pool(coin), Error::::PoolExists); }); @@ -129,13 +132,13 @@ fn create_same_pool_twice_should_fail() { fn different_pools_should_have_different_lp_tokens() { new_test_ext().execute_with(|| { let coin1 = Coin::native(); - let coin2 = Coin::Bitcoin; - let coin3 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Bitcoin); + let coin3 = Coin::External(ExternalCoin::Ether); let pool_id_1_2 = Dex::get_pool_id(coin1, coin2).unwrap(); let pool_id_1_3 = Dex::get_pool_id(coin1, coin3).unwrap(); let lp_token2_1 = coin2; - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); let lp_token3_1 = coin3; assert_eq!( @@ -146,7 +149,7 @@ fn different_pools_should_have_different_lp_tokens() { }] ); - assert_ok!(Dex::create_pool(coin3)); + assert_ok!(Dex::create_pool(coin3.try_into().unwrap())); assert_eq!( events(), [Event::::PoolCreated { @@ -164,13 +167,13 @@ fn can_add_liquidity() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Dai; - let coin3 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Dai); + let coin3 = Coin::External(ExternalCoin::Monero); let lp_token1 = coin2; - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); let lp_token2 = coin3; - assert_ok!(Dex::create_pool(coin3)); + assert_ok!(Dex::create_pool(coin3.try_into().unwrap())); assert_ok!(CoinsPallet::::mint( user, @@ -179,7 +182,15 @@ fn can_add_liquidity() { assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin3, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 10, + 10000, + 10, + 10000, + user, + )); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); assert!(events().contains(&Event::::LiquidityAdded { @@ -198,7 +209,15 @@ fn can_add_liquidity() { assert_eq!(pool_balance(user, lp_token1), 216); // try to pass the non-native - native coins, the result should be the same - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin3, 10, 10000, 10, 10000, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin3.try_into().unwrap(), + 10, + 10000, + 10, + 10000, + user, + )); let pool_id = Dex::get_pool_id(coin1, coin3).unwrap(); assert!(events().contains(&Event::::LiquidityAdded { @@ -223,12 +242,15 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Bitcoin; + let coin2 = ExternalCoin::Bitcoin; assert_ok!(Dex::create_pool(coin2)); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(1000) })); - assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint( + user, + Balance { coin: coin2.into(), amount: Amount(1000) } + )); assert_noop!( Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 1, 1, 1, 1, user), @@ -242,11 +264,11 @@ fn add_tiny_liquidity_directly_to_pool_address() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Ether; - let coin3 = Coin::Dai; + let coin2 = Coin::External(ExternalCoin::Ether); + let coin3 = Coin::External(ExternalCoin::Dai); - assert_ok!(Dex::create_pool(coin2)); - assert_ok!(Dex::create_pool(coin3)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); + assert_ok!(Dex::create_pool(coin3.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000 * 2) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(10000) })); @@ -259,7 +281,15 @@ fn add_tiny_liquidity_directly_to_pool_address() { Balance { coin: coin1, amount: Amount(1000) } )); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 10, + 10000, + 10, + 10000, + user, + )); // check the same but for coin3 (non-native token) let pallet_account = Dex::get_pool_account(Dex::get_pool_id(coin1, coin3).unwrap()); @@ -267,7 +297,15 @@ fn add_tiny_liquidity_directly_to_pool_address() { pallet_account, Balance { coin: coin2, amount: Amount(1) } )); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin3, 10, 10000, 10, 10000, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin3.try_into().unwrap(), + 10, + 10000, + 10, + 10000, + user, + )); }); } @@ -276,11 +314,11 @@ fn can_remove_liquidity() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Monero); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); let lp_token = coin2; - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint( user, @@ -290,7 +328,7 @@ fn can_remove_liquidity() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), 100000, 1000000000, 100000, @@ -302,7 +340,7 @@ fn can_remove_liquidity() { assert_ok!(Dex::remove_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), total_lp_received, 0, 0, @@ -334,15 +372,23 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Dai; + let coin2 = Coin::External(ExternalCoin::Dai); let lp_token = coin2; - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 10, + 10000, + 10, + 10000, + user, + )); // Only 216 lp_tokens_minted assert_eq!(pool_balance(user, lp_token), 216); @@ -350,7 +396,7 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { assert_noop!( Dex::remove_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), 216 + 1, // Try and redeem 10 lp tokens while only 9 minted. 0, 0, @@ -366,14 +412,22 @@ fn can_quote_price() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Ether); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(100000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 200, + 10000, + 1, + 1, + user, + )); assert_eq!( Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, 3000, false,), @@ -481,14 +535,22 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { let user = system_address(b"user1").into(); let user2 = system_address(b"user2").into(); let coin1 = Coin::native(); - let coin2 = Coin::Bitcoin; + let coin2 = Coin::External(ExternalCoin::Bitcoin); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(100000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 200, + 10000, + 1, + 1, + user, + )); let amount = 1; let quoted_price = 49; @@ -518,14 +580,22 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { let user = system_address(b"user1").into(); let user2 = system_address(b"user2").into(); let coin1 = Coin::native(); - let coin2 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Monero); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(100000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 200, + 10000, + 1, + 1, + user, + )); let amount = 49; let quoted_price = 1; @@ -557,10 +627,10 @@ fn can_swap_with_native() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Ether); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); @@ -570,7 +640,7 @@ fn can_swap_with_native() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -602,8 +672,8 @@ fn can_swap_with_realistic_values() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let sri = Coin::native(); - let dai = Coin::Dai; - assert_ok!(Dex::create_pool(dai)); + let dai = Coin::External(ExternalCoin::Dai); + assert_ok!(Dex::create_pool(dai.try_into().unwrap())); const UNIT: u64 = 1_000_000_000; @@ -620,7 +690,7 @@ fn can_swap_with_realistic_values() { let liquidity_dai = 1_000_000 * UNIT; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - dai, + dai.try_into().unwrap(), liquidity_dai, liquidity_sri, 1, @@ -653,9 +723,9 @@ fn can_not_swap_in_pool_with_no_liquidity_added_yet() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Monero); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); // Check can't swap an empty pool assert_noop!( @@ -676,11 +746,11 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Bitcoin; + let coin2 = Coin::External(ExternalCoin::Bitcoin); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); let lp_token = coin2; - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); @@ -690,7 +760,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -714,7 +784,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(Dex::remove_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), lp_token_minted, 1, 1, @@ -787,9 +857,9 @@ fn swap_should_not_work_if_too_much_slippage() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Ether); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); @@ -799,7 +869,7 @@ fn swap_should_not_work_if_too_much_slippage() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -827,10 +897,10 @@ fn can_swap_tokens_for_exact_tokens() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Dai; + let coin2 = Coin::External(ExternalCoin::Dai); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(20000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); @@ -844,7 +914,7 @@ fn can_swap_tokens_for_exact_tokens() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -882,11 +952,11 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { let user = system_address(b"user1").into(); let user2 = system_address(b"user2").into(); let coin1 = Coin::native(); - let coin2 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Monero); let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); let lp_token = coin2; - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); let base1 = 10000; let base2 = 1000; @@ -903,7 +973,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user2), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -947,7 +1017,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(Dex::remove_liquidity( RuntimeOrigin::signed(user2), - coin2, + coin2.try_into().unwrap(), lp_token_minted, 0, 0, @@ -961,9 +1031,9 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Ether); - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(20000) })); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); @@ -973,7 +1043,7 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -1001,11 +1071,11 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Dai; - let coin3 = Coin::Monero; + let coin2 = Coin::External(ExternalCoin::Dai); + let coin3 = Coin::External(ExternalCoin::Monero); - assert_ok!(Dex::create_pool(coin2)); - assert_ok!(Dex::create_pool(coin3)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); + assert_ok!(Dex::create_pool(coin3.try_into().unwrap())); let base1 = 10000; let base2 = 10000; @@ -1019,7 +1089,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -1028,7 +1098,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { )); assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin3, + coin3.try_into().unwrap(), liquidity3, liquidity1, 1, @@ -1089,11 +1159,11 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let coin1 = Coin::native(); - let coin2 = Coin::Bitcoin; - let coin3 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Bitcoin); + let coin3 = Coin::External(ExternalCoin::Ether); - assert_ok!(Dex::create_pool(coin2)); - assert_ok!(Dex::create_pool(coin3)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); + assert_ok!(Dex::create_pool(coin3.try_into().unwrap())); let base1 = 10000; let base2 = 10000; @@ -1107,7 +1177,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin2, + coin2.try_into().unwrap(), liquidity2, liquidity1, 1, @@ -1116,7 +1186,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { )); assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - coin3, + coin3.try_into().unwrap(), liquidity3, liquidity1, 1, @@ -1154,7 +1224,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { fn can_not_swap_same_coin() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let coin1 = Coin::Dai; + let coin1 = Coin::External(ExternalCoin::Dai); assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(1000) })); let exchange_amount = 10; @@ -1188,10 +1258,10 @@ fn validate_pool_id_sorting() { // Serai < Bitcoin < Ether < Dai < Monero. // coin1 <= coin2 for this test to pass. let native = Coin::native(); - let coin1 = Coin::Bitcoin; - let coin2 = Coin::Monero; - assert_eq!(Dex::get_pool_id(native, coin2).unwrap(), coin2); - assert_eq!(Dex::get_pool_id(coin2, native).unwrap(), coin2); + let coin1 = Coin::External(ExternalCoin::Bitcoin); + let coin2 = Coin::External(ExternalCoin::Monero); + assert_eq!(Dex::get_pool_id(native, coin2).unwrap(), coin2.try_into().unwrap()); + assert_eq!(Dex::get_pool_id(coin2, native).unwrap(), coin2.try_into().unwrap()); assert!(matches!(Dex::get_pool_id(native, native), Err(Error::::EqualCoins))); assert!(matches!(Dex::get_pool_id(coin2, coin1), Err(Error::::PoolNotFound))); assert!(coin2 > coin1); @@ -1216,7 +1286,7 @@ fn cannot_block_pool_creation() { // The target pool the user wants to create is Native <=> Coin(2) let coin1 = Coin::native(); - let coin2 = Coin::Ether; + let coin2 = Coin::External(ExternalCoin::Ether); // Attacker computes the still non-existing pool account for the target pair let pool_account = Dex::get_pool_account(Dex::get_pool_id(coin2, coin1).unwrap()); @@ -1238,7 +1308,7 @@ fn cannot_block_pool_creation() { } // User can still create the pool - assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin2.try_into().unwrap())); // User has to transfer one Coin(2) token to the pool account (otherwise add_liquidity will // fail with `CoinTwoDepositDidNotMeetMinimum`), also transfer native token for the same error. @@ -1256,7 +1326,15 @@ fn cannot_block_pool_creation() { )); // add_liquidity shouldn't fail because of the number of consumers - assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 100, 9900, 10, 9900, user,)); + assert_ok!(Dex::add_liquidity( + RuntimeOrigin::signed(user), + coin2.try_into().unwrap(), + 100, + 9900, + 10, + 9900, + user, + )); }); } @@ -1281,7 +1359,7 @@ fn test_median_price() { prices.push(OsRng.next_u64()); } } - let coin = Coin::Bitcoin; + let coin = ExternalCoin::Bitcoin; assert!(prices.len() >= (2 * usize::from(MEDIAN_PRICE_WINDOW_LENGTH))); for i in 0 .. prices.len() { diff --git a/substrate/economic-security/pallet/src/lib.rs b/substrate/economic-security/pallet/src/lib.rs index 65b827941..045297f46 100644 --- a/substrate/economic-security/pallet/src/lib.rs +++ b/substrate/economic-security/pallet/src/lib.rs @@ -24,7 +24,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] pub enum Event { - EconomicSecurityReached { network: NetworkId }, + EconomicSecurityReached { network: ExternalNetworkId }, } #[pallet::pallet] @@ -33,17 +33,19 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn economic_security_block)] pub(crate) type EconomicSecurityBlock = - StorageMap<_, Identity, NetworkId, BlockNumberFor, OptionQuery>; + StorageMap<_, Identity, ExternalNetworkId, BlockNumberFor, OptionQuery>; #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(n: BlockNumberFor) -> Weight { // we accept we reached economic security once we can mint smallest amount of a network's coin - for coin in COINS { + for coin in EXTERNAL_COINS { let existing = EconomicSecurityBlock::::get(coin.network()); + // TODO: we don't need to check for oracle value if is_allowed returns false when there is + // no coin value if existing.is_none() && Dex::::security_oracle_value(coin).is_some() && - ::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) }) + ::AllowMint::is_allowed(&ExternalBalance { coin, amount: Amount(1) }) { EconomicSecurityBlock::::set(coin.network(), Some(n)); Self::deposit_event(Event::EconomicSecurityReached { network: coin.network() }); diff --git a/substrate/emissions/pallet/src/lib.rs b/substrate/emissions/pallet/src/lib.rs index 400f89212..99e22e8bd 100644 --- a/substrate/emissions/pallet/src/lib.rs +++ b/substrate/emissions/pallet/src/lib.rs @@ -84,7 +84,8 @@ pub mod pallet { pub type CurrentSession = StorageMap<_, Identity, NetworkId, u32, ValueQuery>; #[pallet::storage] - pub(crate) type LastSwapVolume = StorageMap<_, Identity, Coin, u64, OptionQuery>; + pub(crate) type LastSwapVolume = + StorageMap<_, Identity, ExternalCoin, u64, OptionQuery>; #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { @@ -136,19 +137,16 @@ pub mod pallet { let mut total_distance: u64 = 0; let reward_this_epoch = if pre_ec_security { // calculate distance to economic security per network - for n in NETWORKS { - if n == NetworkId::Serai { - continue; - } - + for n in EXTERNAL_NETWORKS { let required = ValidatorSets::::required_stake_for_network(n); - let mut current = ValidatorSets::::total_allocated_stake(n).unwrap_or(Amount(0)).0; + let mut current = + ValidatorSets::::total_allocated_stake(NetworkId::from(n)).unwrap_or(Amount(0)).0; if current > required { current = required; } let distance = required - current; - distances.insert(n, distance); + distances.insert(NetworkId::from(n), distance); total_distance = total_distance.saturating_add(distance); } @@ -192,9 +190,8 @@ pub mod pallet { ) } else { // get swap volumes - let mut volume_per_coin: BTreeMap = BTreeMap::new(); - for c in COINS { - // this should return 0 for SRI and so it shouldn't affect the total volume. + let mut volume_per_coin: BTreeMap = BTreeMap::new(); + for c in EXTERNAL_COINS { let current_volume = Dex::::swap_volume(c).unwrap_or(0); let last_volume = LastSwapVolume::::get(c).unwrap_or(0); let vol_this_epoch = current_volume.saturating_sub(last_volume); @@ -209,11 +206,13 @@ pub mod pallet { let mut volume_per_network: BTreeMap = BTreeMap::new(); for (c, vol) in &volume_per_coin { volume_per_network.insert( - c.network(), - (*volume_per_network.get(&c.network()).unwrap_or(&0)).saturating_add(*vol), + c.network().into(), + (*volume_per_network.get(&c.network().into()).unwrap_or(&0)).saturating_add(*vol), ); total_volume = total_volume.saturating_add(*vol); } + // we add the serai network now + volume_per_network.insert(NetworkId::Serai, 0); ( volume_per_network @@ -245,12 +244,13 @@ pub mod pallet { // distribute the rewards within the network for (n, reward) in rewards_per_network { - let (validators_reward, network_pool_reward) = if n == NetworkId::Serai { - (reward, 0) - } else { + let validators_reward = if let NetworkId::External(external_network) = n { // calculate pool vs validator share - let capacity = ValidatorSets::::total_allocated_stake(n).unwrap_or(Amount(0)).0; - let required = ValidatorSets::::required_stake_for_network(n); + let capacity = + ValidatorSets::::total_allocated_stake(NetworkId::from(external_network)) + .unwrap_or(Amount(0)) + .0; + let required = ValidatorSets::::required_stake_for_network(external_network); let unused_capacity = capacity.saturating_sub(required); let distribution = unused_capacity.saturating_mul(ACCURACY_MULTIPLIER) / capacity; @@ -258,41 +258,44 @@ pub mod pallet { let validators_reward = DESIRED_DISTRIBUTION.saturating_mul(reward) / total; let network_pool_reward = reward.saturating_sub(validators_reward); - (validators_reward, network_pool_reward) - }; - // distribute validators rewards - Self::distribute_to_validators(n, validators_reward); + // send the rest to the pool + if network_pool_reward != 0 { + // these should be available to unwrap if we have a network_pool_reward. Because that + // means we had an unused capacity hence in a post-ec era. + let vpn = volume_per_network.as_ref().unwrap(); + let vpc = volume_per_coin.as_ref().unwrap(); + for c in external_network.coins() { + let pool_reward = u64::try_from( + u128::from(network_pool_reward).saturating_mul(u128::from(vpc[&c])) / + u128::from(vpn[&n]), + ) + .unwrap(); - // send the rest to the pool - if network_pool_reward != 0 { - // these should be available to unwrap if we have a network_pool_reward. Because that - // means we had an unused capacity hence in a post-ec era. - let vpn = volume_per_network.as_ref().unwrap(); - let vpc = volume_per_coin.as_ref().unwrap(); - for c in n.coins() { - let pool_reward = u64::try_from( - u128::from(network_pool_reward).saturating_mul(u128::from(vpc[c])) / - u128::from(vpn[&n]), - ) - .unwrap(); - - if Coins::::mint( - Dex::::get_pool_account(*c), - Balance { coin: Coin::Serai, amount: Amount(pool_reward) }, - ) - .is_err() - { - // TODO: log the failure - continue; + if Coins::::mint( + Dex::::get_pool_account(c), + Balance { coin: Coin::Serai, amount: Amount(pool_reward) }, + ) + .is_err() + { + // TODO: log the failure + continue; + } } } - } + + validators_reward + } else { + reward + }; + + // distribute validators rewards + Self::distribute_to_validators(n, validators_reward); } // TODO: we have the past session participants here in the emissions pallet so that we can // distribute rewards to them in the next session. Ideally we should be able to fetch this - // information from valiadtor sets pallet. + // information from validator sets pallet. Self::update_participants(); Weight::zero() // TODO } @@ -318,11 +321,7 @@ pub mod pallet { /// Returns true if any of the external networks haven't reached economic security yet. fn pre_ec_security() -> bool { - for n in NETWORKS { - if n == NetworkId::Serai { - continue; - } - + for n in EXTERNAL_NETWORKS { if EconomicSecurity::::economic_security_block(n).is_none() { return true; } @@ -362,16 +361,30 @@ pub mod pallet { pub fn swap_to_staked_sri( to: PublicKey, network: NetworkId, - balance: Balance, + balance: ExternalBalance, ) -> DispatchResult { // check the network didn't reach the economic security yet - if EconomicSecurity::::economic_security_block(network).is_some() { - Err(Error::::NetworkHasEconomicSecurity)?; + if let NetworkId::External(n) = network { + if EconomicSecurity::::economic_security_block(n).is_some() { + Err(Error::::NetworkHasEconomicSecurity)?; + } + } else { + // we target 20% of the network's stake to be behind the Serai network + let mut total_stake = 0; + for n in NETWORKS { + total_stake += ValidatorSets::::total_allocated_stake(n).unwrap_or(Amount(0)).0; + } + + let stake = ValidatorSets::::total_allocated_stake(network).unwrap_or(Amount(0)).0; + let desired_stake = total_stake / (100 / SERAI_VALIDATORS_DESIRED_PERCENTAGE); + if stake >= desired_stake { + Err(Error::::NetworkHasEconomicSecurity)?; + } } // swap half of the liquidity for SRI to form PoL. let half = balance.amount.0 / 2; - let path = BoundedVec::try_from(vec![balance.coin, Coin::Serai]).unwrap(); + let path = BoundedVec::try_from(vec![balance.coin.into(), Coin::Serai]).unwrap(); let origin = RawOrigin::Signed(POL_ACCOUNT.into()); Dex::::swap_exact_tokens_for_tokens( origin.clone().into(), diff --git a/substrate/genesis-liquidity/pallet/src/lib.rs b/substrate/genesis-liquidity/pallet/src/lib.rs index c9e4e4f41..3a78e4930 100644 --- a/substrate/genesis-liquidity/pallet/src/lib.rs +++ b/substrate/genesis-liquidity/pallet/src/lib.rs @@ -54,9 +54,9 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] pub enum Event { - GenesisLiquidityAdded { by: SeraiAddress, balance: Balance }, - GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance }, - GenesisLiquidityAddedToPool { coin1: Balance, sri: Amount }, + GenesisLiquidityAdded { by: SeraiAddress, balance: ExternalBalance }, + GenesisLiquidityRemoved { by: SeraiAddress, balance: ExternalBalance }, + GenesisLiquidityAddedToPool { coin: ExternalBalance, sri: Amount }, } #[pallet::pallet] @@ -64,15 +64,23 @@ pub mod pallet { /// Keeps shares and the amount of coins per account. #[pallet::storage] - pub(crate) type Liquidity = - StorageDoubleMap<_, Identity, Coin, Blake2_128Concat, PublicKey, LiquidityAmount, OptionQuery>; + pub(crate) type Liquidity = StorageDoubleMap< + _, + Identity, + ExternalCoin, + Blake2_128Concat, + PublicKey, + LiquidityAmount, + OptionQuery, + >; /// Keeps the total shares and the total amount of coins per coin. #[pallet::storage] - pub(crate) type Supply = StorageMap<_, Identity, Coin, LiquidityAmount, OptionQuery>; + pub(crate) type Supply = + StorageMap<_, Identity, ExternalCoin, LiquidityAmount, OptionQuery>; #[pallet::storage] - pub(crate) type Oracle = StorageMap<_, Identity, Coin, u64, OptionQuery>; + pub(crate) type Oracle = StorageMap<_, Identity, ExternalCoin, u64, OptionQuery>; #[pallet::storage] #[pallet::getter(fn genesis_complete_block)] @@ -102,11 +110,7 @@ pub mod pallet { // get pool & total values let mut pool_values = vec![]; let mut total_value: u128 = 0; - for coin in COINS { - if coin == Coin::Serai { - continue; - } - + for coin in EXTERNAL_COINS { // initial coin value in terms of btc let Some(value) = Oracle::::get(coin) else { continue; @@ -158,7 +162,7 @@ pub mod pallet { // let everyone know about the event Self::deposit_event(Event::GenesisLiquidityAddedToPool { - coin1: Balance { coin, amount: Amount(u64::try_from(pool_amount).unwrap()) }, + coin: ExternalBalance { coin, amount: Amount(u64::try_from(pool_amount).unwrap()) }, sri: Amount(sri_amount), }); } @@ -180,7 +184,7 @@ pub mod pallet { impl Pallet { /// Add genesis liquidity for the given account. All accounts that provide liquidity /// will receive the genesis SRI according to their liquidity ratio. - pub fn add_coin_liquidity(account: PublicKey, balance: Balance) -> DispatchResult { + pub fn add_coin_liquidity(account: PublicKey, balance: ExternalBalance) -> DispatchResult { // check we are still in genesis period if Self::genesis_ended() { Err(Error::::GenesisPeriodEnded)?; @@ -227,7 +231,7 @@ pub mod pallet { /// If networks is yet to be reached that threshold, None is returned. fn blocks_since_ec_security() -> Option { let mut min = u64::MAX; - for n in NETWORKS { + for n in EXTERNAL_NETWORKS { let ec_security_block = EconomicSecurity::::economic_security_block(n)?.saturated_into::(); let current = >::block_number().saturated_into::(); @@ -243,11 +247,7 @@ pub mod pallet { } fn oraclization_is_done() -> bool { - for c in COINS { - if c == Coin::Serai { - continue; - } - + for c in EXTERNAL_COINS { if Oracle::::get(c).is_none() { return false; } @@ -276,7 +276,7 @@ pub mod pallet { /// Remove the provided genesis liquidity for an account. #[pallet::call_index(0)] #[pallet::weight((0, DispatchClass::Operational))] // TODO - pub fn remove_coin_liquidity(origin: OriginFor, balance: Balance) -> DispatchResult { + pub fn remove_coin_liquidity(origin: OriginFor, balance: ExternalBalance) -> DispatchResult { let account = ensure_signed(origin)?; let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into()); let supply = Supply::::get(balance.coin).ok_or(Error::::NotEnoughLiquidity)?; @@ -297,7 +297,7 @@ pub mod pallet { // remove liquidity from pool let prev_sri = Coins::::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai); - let prev_coin = Coins::::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin); + let prev_coin = Coins::::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin.into()); Dex::::remove_liquidity( origin.clone().into(), balance.coin, @@ -307,7 +307,8 @@ pub mod pallet { GENESIS_LIQUIDITY_ACCOUNT.into(), )?; let current_sri = Coins::::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai); - let current_coin = Coins::::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin); + let current_coin = + Coins::::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin.into()); // burn the SRI if necessary // TODO: take into consideration movement between pools. @@ -333,7 +334,7 @@ pub mod pallet { Coins::::transfer( origin.clone().into(), account, - Balance { coin: balance.coin, amount: Amount(coin_out) }, + Balance { coin: balance.coin.into(), amount: Amount(coin_out) }, )?; Coins::::transfer( origin.into(), @@ -366,7 +367,7 @@ pub mod pallet { Coins::::transfer( origin.into(), account, - Balance { coin: balance.coin, amount: Amount(existing.coins) }, + Balance { coin: balance.coin.into(), amount: Amount(existing.coins) }, )?; ( @@ -404,10 +405,10 @@ pub mod pallet { ensure_none(origin)?; // set their relative values - Oracle::::set(Coin::Bitcoin, Some(10u64.pow(Coin::Bitcoin.decimals()))); - Oracle::::set(Coin::Monero, Some(values.monero)); - Oracle::::set(Coin::Ether, Some(values.ether)); - Oracle::::set(Coin::Dai, Some(values.dai)); + Oracle::::set(ExternalCoin::Bitcoin, Some(10u64.pow(ExternalCoin::Bitcoin.decimals()))); + Oracle::::set(ExternalCoin::Monero, Some(values.monero)); + Oracle::::set(ExternalCoin::Ether, Some(values.ether)); + Oracle::::set(ExternalCoin::Dai, Some(values.dai)); Ok(()) } } diff --git a/substrate/in-instructions/pallet/src/lib.rs b/substrate/in-instructions/pallet/src/lib.rs index f90ae4122..e3f69f417 100644 --- a/substrate/in-instructions/pallet/src/lib.rs +++ b/substrate/in-instructions/pallet/src/lib.rs @@ -4,7 +4,7 @@ use sp_io::hashing::blake2_256; -use serai_primitives::{BlockHash, NetworkId}; +use serai_primitives::*; pub use in_instructions_primitives as primitives; use primitives::*; @@ -23,8 +23,6 @@ pub mod pallet { use sp_runtime::traits::Zero; use sp_core::sr25519::Public; - use serai_primitives::{Coin, Amount, Balance}; - use frame_support::pallet_prelude::*; use frame_system::{pallet_prelude::*, RawOrigin}; @@ -34,7 +32,7 @@ pub mod pallet { }; use dex_pallet::{Config as DexConfig, Pallet as Dex}; use validator_sets_pallet::{ - primitives::{Session, ValidatorSet}, + primitives::{Session, ValidatorSet, ExternalValidatorSet}, Config as ValidatorSetsConfig, Pallet as ValidatorSets, }; @@ -60,9 +58,9 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] pub enum Event { - Batch { network: NetworkId, id: u32, block: BlockHash, instructions_hash: [u8; 32] }, - InstructionFailure { network: NetworkId, id: u32, index: u32 }, - Halt { network: NetworkId }, + Batch { network: ExternalNetworkId, id: u32, block: BlockHash, instructions_hash: [u8; 32] }, + InstructionFailure { network: ExternalNetworkId, id: u32, index: u32 }, + Halt { network: ExternalNetworkId }, } #[pallet::error] @@ -77,23 +75,24 @@ pub mod pallet { // The ID of the last executed Batch for a network. #[pallet::storage] #[pallet::getter(fn batches)] - pub(crate) type LastBatch = StorageMap<_, Identity, NetworkId, u32, OptionQuery>; + pub(crate) type LastBatch = + StorageMap<_, Identity, ExternalNetworkId, u32, OptionQuery>; // The last Serai block in which this validator set included a batch #[pallet::storage] #[pallet::getter(fn last_batch_block)] pub(crate) type LastBatchBlock = - StorageMap<_, Identity, NetworkId, BlockNumberFor, OptionQuery>; + StorageMap<_, Identity, ExternalNetworkId, BlockNumberFor, OptionQuery>; // Halted networks. #[pallet::storage] - pub(crate) type Halted = StorageMap<_, Identity, NetworkId, (), OptionQuery>; + pub(crate) type Halted = StorageMap<_, Identity, ExternalNetworkId, (), OptionQuery>; // The latest block a network has acknowledged as finalized #[pallet::storage] #[pallet::getter(fn latest_network_block)] pub(crate) type LatestNetworkBlock = - StorageMap<_, Identity, NetworkId, BlockHash, OptionQuery>; + StorageMap<_, Identity, ExternalNetworkId, BlockHash, OptionQuery>; impl Pallet { // Use a dedicated transaction layer when executing this InInstruction @@ -102,7 +101,7 @@ pub mod pallet { fn execute(instruction: InInstructionWithBalance) -> Result<(), DispatchError> { match instruction.instruction { InInstruction::Transfer(address) => { - Coins::::mint(address.into(), instruction.balance)?; + Coins::::mint(address.into(), instruction.balance.into())?; } InInstruction::Dex(call) => { // This will only be initiated by external chain transactions. That is why we only need @@ -114,11 +113,11 @@ pub mod pallet { let coin = instruction.balance.coin; // mint the given coin on the account - Coins::::mint(IN_INSTRUCTION_EXECUTOR.into(), instruction.balance)?; + Coins::::mint(IN_INSTRUCTION_EXECUTOR.into(), instruction.balance.into())?; // swap half of it for SRI let half = instruction.balance.amount.0 / 2; - let path = BoundedVec::try_from(vec![coin, Coin::Serai]).unwrap(); + let path = BoundedVec::try_from(vec![coin.into(), Coin::Serai]).unwrap(); Dex::::swap_exact_tokens_for_tokens( origin.clone().into(), path, @@ -144,13 +143,13 @@ pub mod pallet { // TODO: minimums are set to 1 above to guarantee successful adding liq call. // Ideally we either get this info from user or send the leftovers back to user. // Let's send the leftovers back to user for now. - let coin_balance = Coins::::balance(IN_INSTRUCTION_EXECUTOR.into(), coin); + let coin_balance = Coins::::balance(IN_INSTRUCTION_EXECUTOR.into(), coin.into()); let sri_balance = Coins::::balance(IN_INSTRUCTION_EXECUTOR.into(), Coin::Serai); if coin_balance != Amount(0) { Coins::::transfer_internal( IN_INSTRUCTION_EXECUTOR.into(), address.into(), - Balance { coin, amount: coin_balance }, + Balance { coin: coin.into(), amount: coin_balance }, )?; } if sri_balance != Amount(0) { @@ -171,10 +170,10 @@ pub mod pallet { } // mint the given coin on our account - Coins::::mint(IN_INSTRUCTION_EXECUTOR.into(), instruction.balance)?; + Coins::::mint(IN_INSTRUCTION_EXECUTOR.into(), instruction.balance.into())?; // get the path - let mut path = vec![instruction.balance.coin, Coin::Serai]; + let mut path = vec![instruction.balance.coin.into(), Coin::Serai]; if !native_coin { path.push(out_balance.coin); } @@ -210,7 +209,10 @@ pub mod pallet { // TODO: Properly pass data. Replace address with an OutInstruction entirely? data: None, }, - balance: Balance { coin: out_balance.coin, amount: coin_balance }, + balance: ExternalBalance { + coin: out_balance.coin.try_into().unwrap(), + amount: coin_balance, + }, }; Coins::::burn_with_instruction(origin.into(), instruction)?; } @@ -218,18 +220,18 @@ pub mod pallet { } } InInstruction::GenesisLiquidity(address) => { - Coins::::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), instruction.balance)?; + Coins::::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), instruction.balance.into())?; GenesisLiq::::add_coin_liquidity(address.into(), instruction.balance)?; } InInstruction::SwapToStakedSRI(address, network) => { - Coins::::mint(POL_ACCOUNT.into(), instruction.balance)?; + Coins::::mint(POL_ACCOUNT.into(), instruction.balance.into())?; Emissions::::swap_to_staked_sri(address.into(), network, instruction.balance)?; } } Ok(()) } - pub fn halt(network: NetworkId) -> Result<(), DispatchError> { + pub fn halt(network: ExternalNetworkId) -> Result<(), DispatchError> { Halted::::set(network, Some(())); Self::deposit_event(Event::Halt { network }); Ok(()) @@ -237,13 +239,13 @@ pub mod pallet { } fn keys_for_network( - network: NetworkId, + network: ExternalNetworkId, ) -> Result<(Session, Option, Option), InvalidTransaction> { // If there's no session set, and therefore no keys set, then this must be an invalid signature - let Some(session) = ValidatorSets::::session(network) else { + let Some(session) = ValidatorSets::::session(NetworkId::from(network)) else { Err(InvalidTransaction::BadProof)? }; - let mut set = ValidatorSet { session, network }; + let mut set = ExternalValidatorSet { network, session }; let latest = ValidatorSets::::keys(set).map(|keys| keys.0); let prior = if set.session.0 != 0 { set.session.0 -= 1; @@ -303,12 +305,7 @@ pub mod pallet { if batch.batch.encode().len() > MAX_BATCH_SIZE { Err(InvalidTransaction::ExhaustsResources)?; } - let network = batch.batch.network; - // Don't allow the Serai set to publish `Batch`s as-if Serai itself was an external network - if network == NetworkId::Serai { - Err(InvalidTransaction::Custom(0))?; - } // verify the signature let (current_session, prior, current) = keys_for_network::(network)?; @@ -336,7 +333,7 @@ pub mod pallet { // `Batch`s published by the prior key, meaning they are accepting the hand-over. if prior.is_some() && (!valid_by_prior) { ValidatorSets::::retire_set(ValidatorSet { - network, + network: network.into(), session: Session(current_session.0 - 1), }); } diff --git a/substrate/in-instructions/primitives/src/lib.rs b/substrate/in-instructions/primitives/src/lib.rs index 1455e4236..3944fd731 100644 --- a/substrate/in-instructions/primitives/src/lib.rs +++ b/substrate/in-instructions/primitives/src/lib.rs @@ -20,7 +20,7 @@ use sp_std::vec::Vec; use sp_runtime::RuntimeDebug; #[rustfmt::skip] -use serai_primitives::{BlockHash, Balance, NetworkId, SeraiAddress, ExternalAddress, system_address}; +use serai_primitives::{BlockHash, Balance, ExternalNetworkId, NetworkId, SeraiAddress, ExternalBalance, ExternalAddress, system_address}; mod shorthand; pub use shorthand::*; @@ -97,7 +97,7 @@ pub struct RefundableInInstruction { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct InInstructionWithBalance { pub instruction: InInstruction, - pub balance: Balance, + pub balance: ExternalBalance, } #[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)] @@ -105,7 +105,7 @@ pub struct InInstructionWithBalance { #[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Batch { - pub network: NetworkId, + pub network: ExternalNetworkId, pub id: u32, pub block: BlockHash, pub instructions: Vec, diff --git a/substrate/in-instructions/primitives/src/shorthand.rs b/substrate/in-instructions/primitives/src/shorthand.rs index 8b1103c3b..6f29f6f3d 100644 --- a/substrate/in-instructions/primitives/src/shorthand.rs +++ b/substrate/in-instructions/primitives/src/shorthand.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; -use serai_primitives::{Coin, Amount, SeraiAddress, ExternalAddress}; +use serai_primitives::{Amount, ExternalAddress, ExternalCoin, SeraiAddress}; use coins_primitives::OutInstruction; @@ -25,7 +25,7 @@ pub enum Shorthand { Raw(RefundableInInstruction), Swap { origin: Option, - coin: Coin, + coin: ExternalCoin, minimum: Amount, out: OutInstruction, }, diff --git a/substrate/node/src/chain_spec.rs b/substrate/node/src/chain_spec.rs index e67674cc5..972b4dd6f 100644 --- a/substrate/node/src/chain_spec.rs +++ b/substrate/node/src/chain_spec.rs @@ -33,6 +33,22 @@ fn devnet_genesis( endowed_accounts: Vec, ) -> RuntimeGenesisConfig { let validators = validators.iter().map(|name| account_from_name(name)).collect::>(); + let key_shares = NETWORKS + .iter() + .map(|network| match network { + NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), + NetworkId::External(ExternalNetworkId::Bitcoin) => { + (NetworkId::External(ExternalNetworkId::Bitcoin), Amount(1_000_000 * 10_u64.pow(8))) + } + NetworkId::External(ExternalNetworkId::Ethereum) => { + (NetworkId::External(ExternalNetworkId::Ethereum), Amount(1_000_000 * 10_u64.pow(8))) + } + NetworkId::External(ExternalNetworkId::Monero) => { + (NetworkId::External(ExternalNetworkId::Monero), Amount(100_000 * 10_u64.pow(8))) + } + }) + .collect::>(); + RuntimeGenesisConfig { system: SystemConfig { code: wasm_binary.to_vec(), _config: PhantomData }, @@ -47,29 +63,10 @@ fn devnet_genesis( }, validator_sets: ValidatorSetsConfig { - networks: serai_runtime::primitives::NETWORKS - .iter() - .map(|network| match network { - NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), - NetworkId::Bitcoin => (NetworkId::Bitcoin, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Ethereum => (NetworkId::Ethereum, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Monero => (NetworkId::Monero, Amount(100_000 * 10_u64.pow(8))), - }) - .collect(), - participants: validators.clone(), - }, - emissions: EmissionsConfig { - networks: serai_runtime::primitives::NETWORKS - .iter() - .map(|network| match network { - NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), - NetworkId::Bitcoin => (NetworkId::Bitcoin, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Ethereum => (NetworkId::Ethereum, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Monero => (NetworkId::Monero, Amount(100_000 * 10_u64.pow(8))), - }) - .collect(), + networks: key_shares.clone(), participants: validators.clone(), }, + emissions: EmissionsConfig { networks: key_shares, participants: validators.clone() }, signals: SignalsConfig::default(), babe: BabeConfig { authorities: validators.iter().map(|validator| ((*validator).into(), 1)).collect(), @@ -88,6 +85,21 @@ fn testnet_genesis(wasm_binary: &[u8], validators: Vec<&'static str>) -> Runtime .into_iter() .map(|validator| Public::decode(&mut hex::decode(validator).unwrap().as_slice()).unwrap()) .collect::>(); + let key_shares = NETWORKS + .iter() + .map(|network| match network { + NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), + NetworkId::External(ExternalNetworkId::Bitcoin) => { + (NetworkId::External(ExternalNetworkId::Bitcoin), Amount(1_000_000 * 10_u64.pow(8))) + } + NetworkId::External(ExternalNetworkId::Ethereum) => { + (NetworkId::External(ExternalNetworkId::Ethereum), Amount(1_000_000 * 10_u64.pow(8))) + } + NetworkId::External(ExternalNetworkId::Monero) => { + (NetworkId::External(ExternalNetworkId::Monero), Amount(100_000 * 10_u64.pow(8))) + } + }) + .collect::>(); assert_eq!(validators.iter().collect::>().len(), validators.len()); @@ -105,29 +117,10 @@ fn testnet_genesis(wasm_binary: &[u8], validators: Vec<&'static str>) -> Runtime }, validator_sets: ValidatorSetsConfig { - networks: serai_runtime::primitives::NETWORKS - .iter() - .map(|network| match network { - NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), - NetworkId::Bitcoin => (NetworkId::Bitcoin, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Ethereum => (NetworkId::Ethereum, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Monero => (NetworkId::Monero, Amount(100_000 * 10_u64.pow(8))), - }) - .collect(), - participants: validators.clone(), - }, - emissions: EmissionsConfig { - networks: serai_runtime::primitives::NETWORKS - .iter() - .map(|network| match network { - NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))), - NetworkId::Bitcoin => (NetworkId::Bitcoin, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Ethereum => (NetworkId::Ethereum, Amount(1_000_000 * 10_u64.pow(8))), - NetworkId::Monero => (NetworkId::Monero, Amount(100_000 * 10_u64.pow(8))), - }) - .collect(), + networks: key_shares.clone(), participants: validators.clone(), }, + emissions: EmissionsConfig { networks: key_shares, participants: validators.clone() }, signals: SignalsConfig::default(), babe: BabeConfig { authorities: validators.iter().map(|validator| ((*validator).into(), 1)).collect(), diff --git a/substrate/primitives/Cargo.toml b/substrate/primitives/Cargo.toml index 0e1e8f387..983b17855 100644 --- a/substrate/primitives/Cargo.toml +++ b/substrate/primitives/Cargo.toml @@ -28,6 +28,7 @@ sp-application-crypto = { git = "https://github.com/serai-dex/substrate", defaul sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-io = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } @@ -35,7 +36,7 @@ frame-support = { git = "https://github.com/serai-dex/substrate", default-featur rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } [features] -std = ["zeroize", "scale/std", "borsh?/std", "serde?/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "frame-support/std"] +std = ["zeroize", "scale/std", "borsh?/std", "serde?/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "sp-std/std", "frame-support/std"] borsh = ["dep:borsh"] serde = ["dep:serde"] default = ["std"] diff --git a/substrate/primitives/src/amount.rs b/substrate/primitives/src/amount.rs index 3953b4208..c82fe34d8 100644 --- a/substrate/primitives/src/amount.rs +++ b/substrate/primitives/src/amount.rs @@ -29,6 +29,8 @@ pub type SubstrateAmount = u64; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Amount(pub SubstrateAmount); +// TODO: these impl shouldn't panic and return error to be dealt with. +// Otherwise we might have a panic that stops the network. impl Add for Amount { type Output = Amount; fn add(self, other: Amount) -> Amount { diff --git a/substrate/primitives/src/balance.rs b/substrate/primitives/src/balance.rs index 62182d43f..6743e6fa6 100644 --- a/substrate/primitives/src/balance.rs +++ b/substrate/primitives/src/balance.rs @@ -11,7 +11,7 @@ use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; -use crate::{Coin, Amount}; +use crate::{Amount, Coin, ExternalCoin}; /// The type used for balances (a Coin and Balance). #[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] @@ -23,6 +23,34 @@ pub struct Balance { pub amount: Amount, } +/// The type used for balances (a Coin and Balance). +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ExternalBalance { + pub coin: ExternalCoin, + pub amount: Amount, +} + +impl From for Balance { + fn from(balance: ExternalBalance) -> Self { + Balance { coin: balance.coin.into(), amount: balance.amount } + } +} + +impl TryFrom for ExternalBalance { + type Error = (); + + fn try_from(balance: Balance) -> Result { + match balance.coin { + Coin::Serai => Err(())?, + Coin::External(coin) => Ok(ExternalBalance { coin, amount: balance.amount }), + } + } +} + +// TODO: these impl either should be removed or return errors in case of overflows impl Add for Balance { type Output = Balance; fn add(self, other: Amount) -> Balance { diff --git a/substrate/primitives/src/networks.rs b/substrate/primitives/src/networks.rs index 1213378c4..64cf7cc2e 100644 --- a/substrate/primitives/src/networks.rs +++ b/substrate/primitives/src/networks.rs @@ -1,7 +1,7 @@ #[cfg(feature = "std")] use zeroize::Zeroize; -use scale::{Encode, Decode, MaxEncodedLen}; +use scale::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "borsh")] @@ -10,54 +10,342 @@ use borsh::{BorshSerialize, BorshDeserialize}; use serde::{Serialize, Deserialize}; use sp_core::{ConstU32, bounded::BoundedVec}; +use sp_std::{vec, vec::Vec}; #[cfg(feature = "borsh")] use crate::{borsh_serialize_bounded_vec, borsh_deserialize_bounded_vec}; -/// The type used to identify networks. -#[derive( - Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, PartialOrd, Ord, MaxEncodedLen, TypeInfo, -)] +/// The type used to identify external networks. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] -#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum NetworkId { - Serai, +pub enum ExternalNetworkId { Bitcoin, Ethereum, Monero, } -impl NetworkId { - pub fn coins(&self) -> &'static [Coin] { + +impl Encode for ExternalNetworkId { + fn encode(&self) -> Vec { match self { - Self::Serai => &[Coin::Serai], - Self::Bitcoin => &[Coin::Bitcoin], - Self::Ethereum => &[Coin::Ether, Coin::Dai], - Self::Monero => &[Coin::Monero], + ExternalNetworkId::Bitcoin => vec![1], + ExternalNetworkId::Ethereum => vec![2], + ExternalNetworkId::Monero => vec![3], } } } -pub const NETWORKS: [NetworkId; 4] = - [NetworkId::Serai, NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero]; +impl Decode for ExternalNetworkId { + fn decode(input: &mut I) -> Result { + let kind = input.read_byte()?; + match kind { + 1 => Ok(Self::Bitcoin), + 2 => Ok(Self::Ethereum), + 3 => Ok(Self::Monero), + _ => Err(scale::Error::from("invalid format")), + } + } +} -pub const COINS: [Coin; 5] = [Coin::Serai, Coin::Bitcoin, Coin::Ether, Coin::Dai, Coin::Monero]; +impl MaxEncodedLen for ExternalNetworkId { + fn max_encoded_len() -> usize { + 1 + } +} -/// The type used to identify coins. -#[derive( - Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +impl EncodeLike for ExternalNetworkId {} + +#[cfg(feature = "borsh")] +impl BorshSerialize for ExternalNetworkId { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(&self.encode()) + } +} + +#[cfg(feature = "borsh")] +impl BorshDeserialize for ExternalNetworkId { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut kind = [0; 1]; + reader.read_exact(&mut kind)?; + ExternalNetworkId::decode(&mut kind.as_slice()) + .map_err(|_| std::io::Error::other("invalid format")) + } +} + +/// The type used to identify networks. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] -#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Coin { +pub enum NetworkId { Serai, + External(ExternalNetworkId), +} + +impl Encode for NetworkId { + fn encode(&self) -> Vec { + match self { + NetworkId::Serai => vec![0], + NetworkId::External(network) => network.encode(), + } + } +} + +impl Decode for NetworkId { + fn decode(input: &mut I) -> Result { + let kind = input.read_byte()?; + match kind { + 0 => Ok(Self::Serai), + _ => Ok(ExternalNetworkId::decode(&mut [kind].as_slice())?.into()), + } + } +} + +impl MaxEncodedLen for NetworkId { + fn max_encoded_len() -> usize { + 1 + } +} + +impl EncodeLike for NetworkId {} + +#[cfg(feature = "borsh")] +impl BorshSerialize for NetworkId { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(&self.encode()) + } +} + +#[cfg(feature = "borsh")] +impl BorshDeserialize for NetworkId { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut kind = [0; 1]; + reader.read_exact(&mut kind)?; + NetworkId::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format")) + } +} + +impl ExternalNetworkId { + pub fn coins(&self) -> Vec { + match self { + Self::Bitcoin => vec![ExternalCoin::Bitcoin], + Self::Ethereum => vec![ExternalCoin::Ether, ExternalCoin::Dai], + Self::Monero => vec![ExternalCoin::Monero], + } + } +} + +impl NetworkId { + pub fn coins(&self) -> Vec { + match self { + Self::Serai => vec![Coin::Serai], + Self::External(network) => { + network.coins().into_iter().map(core::convert::Into::into).collect() + } + } + } +} + +impl From for NetworkId { + fn from(network: ExternalNetworkId) -> Self { + NetworkId::External(network) + } +} + +impl TryFrom for ExternalNetworkId { + type Error = (); + + fn try_from(network: NetworkId) -> Result { + match network { + NetworkId::Serai => Err(())?, + NetworkId::External(n) => Ok(n), + } + } +} + +pub const EXTERNAL_NETWORKS: [ExternalNetworkId; 3] = + [ExternalNetworkId::Bitcoin, ExternalNetworkId::Ethereum, ExternalNetworkId::Monero]; + +pub const NETWORKS: [NetworkId; 4] = [ + NetworkId::Serai, + NetworkId::External(ExternalNetworkId::Bitcoin), + NetworkId::External(ExternalNetworkId::Ethereum), + NetworkId::External(ExternalNetworkId::Monero), +]; + +pub const EXTERNAL_COINS: [ExternalCoin; 4] = + [ExternalCoin::Bitcoin, ExternalCoin::Ether, ExternalCoin::Dai, ExternalCoin::Monero]; + +pub const COINS: [Coin; 5] = [ + Coin::Serai, + Coin::External(ExternalCoin::Bitcoin), + Coin::External(ExternalCoin::Ether), + Coin::External(ExternalCoin::Dai), + Coin::External(ExternalCoin::Monero), +]; + +/// The type used to identify external coins. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum ExternalCoin { Bitcoin, Ether, Dai, Monero, } +impl Encode for ExternalCoin { + fn encode(&self) -> Vec { + match self { + ExternalCoin::Bitcoin => vec![4], + ExternalCoin::Ether => vec![5], + ExternalCoin::Dai => vec![6], + ExternalCoin::Monero => vec![7], + } + } +} + +impl Decode for ExternalCoin { + fn decode(input: &mut I) -> Result { + let kind = input.read_byte()?; + match kind { + 4 => Ok(Self::Bitcoin), + 5 => Ok(Self::Ether), + 6 => Ok(Self::Dai), + 7 => Ok(Self::Monero), + _ => Err(scale::Error::from("invalid format")), + } + } +} +impl MaxEncodedLen for ExternalCoin { + fn max_encoded_len() -> usize { + 1 + } +} + +impl EncodeLike for ExternalCoin {} + +#[cfg(feature = "borsh")] +impl BorshSerialize for ExternalCoin { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(&self.encode()) + } +} + +#[cfg(feature = "borsh")] +impl BorshDeserialize for ExternalCoin { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut kind = [0; 1]; + reader.read_exact(&mut kind)?; + ExternalCoin::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format")) + } +} + +/// The type used to identify coins. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum Coin { + Serai, + External(ExternalCoin), +} + +impl Encode for Coin { + fn encode(&self) -> Vec { + match self { + Coin::Serai => vec![0], + Coin::External(ec) => ec.encode(), + } + } +} + +impl Decode for Coin { + fn decode(input: &mut I) -> Result { + let kind = input.read_byte()?; + match kind { + 0 => Ok(Self::Serai), + _ => Ok(ExternalCoin::decode(&mut [kind].as_slice())?.into()), + } + } +} + +impl MaxEncodedLen for Coin { + fn max_encoded_len() -> usize { + 1 + } +} + +impl EncodeLike for Coin {} + +#[cfg(feature = "borsh")] +impl BorshSerialize for Coin { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(&self.encode()) + } +} + +#[cfg(feature = "borsh")] +impl BorshDeserialize for Coin { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut kind = [0; 1]; + reader.read_exact(&mut kind)?; + Coin::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format")) + } +} + +impl From for Coin { + fn from(coin: ExternalCoin) -> Self { + Coin::External(coin) + } +} + +impl TryFrom for ExternalCoin { + type Error = (); + + fn try_from(coin: Coin) -> Result { + match coin { + Coin::Serai => Err(())?, + Coin::External(c) => Ok(c), + } + } +} + +impl ExternalCoin { + pub fn network(&self) -> ExternalNetworkId { + match self { + ExternalCoin::Bitcoin => ExternalNetworkId::Bitcoin, + ExternalCoin::Ether | ExternalCoin::Dai => ExternalNetworkId::Ethereum, + ExternalCoin::Monero => ExternalNetworkId::Monero, + } + } + + pub fn name(&self) -> &'static str { + match self { + ExternalCoin::Bitcoin => "Bitcoin", + ExternalCoin::Ether => "Ether", + ExternalCoin::Dai => "Dai Stablecoin", + ExternalCoin::Monero => "Monero", + } + } + + pub fn symbol(&self) -> &'static str { + match self { + ExternalCoin::Bitcoin => "BTC", + ExternalCoin::Ether => "ETH", + ExternalCoin::Dai => "DAI", + ExternalCoin::Monero => "XMR", + } + } + + pub fn decimals(&self) -> u32 { + match self { + // Ether and DAI have 18 decimals, yet we only track 8 in order to fit them within u64s + ExternalCoin::Bitcoin | ExternalCoin::Ether | ExternalCoin::Dai => 8, + ExternalCoin::Monero => 12, + } + } +} + impl Coin { pub fn native() -> Coin { Coin::Serai @@ -66,37 +354,28 @@ impl Coin { pub fn network(&self) -> NetworkId { match self { Coin::Serai => NetworkId::Serai, - Coin::Bitcoin => NetworkId::Bitcoin, - Coin::Ether | Coin::Dai => NetworkId::Ethereum, - Coin::Monero => NetworkId::Monero, + Coin::External(c) => c.network().into(), } } pub fn name(&self) -> &'static str { match self { Coin::Serai => "Serai", - Coin::Bitcoin => "Bitcoin", - Coin::Ether => "Ether", - Coin::Dai => "Dai Stablecoin", - Coin::Monero => "Monero", + Coin::External(c) => c.name(), } } pub fn symbol(&self) -> &'static str { match self { Coin::Serai => "SRI", - Coin::Bitcoin => "BTC", - Coin::Ether => "ETH", - Coin::Dai => "DAI", - Coin::Monero => "XMR", + Coin::External(c) => c.symbol(), } } pub fn decimals(&self) -> u32 { match self { - // Ether and DAI have 18 decimals, yet we only track 8 in order to fit them within u64s - Coin::Serai | Coin::Bitcoin | Coin::Ether | Coin::Dai => 8, - Coin::Monero => 12, + Coin::Serai => 8, + Coin::External(c) => c.decimals(), } } diff --git a/substrate/runtime/src/lib.rs b/substrate/runtime/src/lib.rs index e55270cb9..151242712 100644 --- a/substrate/runtime/src/lib.rs +++ b/substrate/runtime/src/lib.rs @@ -53,8 +53,9 @@ use sp_runtime::{ #[allow(unused_imports)] use primitives::{ - NetworkId, PublicKey, AccountLookup, SubstrateAmount, Coin, NETWORKS, MEDIAN_PRICE_WINDOW_LENGTH, - HOURS, DAYS, MINUTES, TARGET_BLOCK_TIME, BLOCK_SIZE, FAST_EPOCH_DURATION, + NetworkId, PublicKey, AccountLookup, SubstrateAmount, Coin, EXTERNAL_NETWORKS, + MEDIAN_PRICE_WINDOW_LENGTH, HOURS, DAYS, MINUTES, TARGET_BLOCK_TIME, BLOCK_SIZE, + FAST_EPOCH_DURATION, }; use support::{ @@ -570,10 +571,7 @@ sp_api::impl_runtime_apis! { .map(|(id, _)| id.into_inner().0) .collect::>(); let mut all = serai_validators; - for network in NETWORKS { - if network == NetworkId::Serai { - continue; - } + for network in EXTERNAL_NETWORKS { // Returning the latest-decided, not latest and active, means the active set // may fail to peer find if there isn't sufficient overlap. If a large amount reboot, // forcing some validators to successfully peer find in order for the threshold to become @@ -581,7 +579,7 @@ sp_api::impl_runtime_apis! { // // This is assumed not to matter in real life, yet an interesting note. let participants = - ValidatorSets::participants_for_latest_decided_set(network) + ValidatorSets::participants_for_latest_decided_set(NetworkId::from(network)) .map_or(vec![], BoundedVec::into_inner); for (participant, _) in participants { all.insert(participant.0); @@ -610,25 +608,25 @@ sp_api::impl_runtime_apis! { impl dex::DexApi for Runtime { fn quote_price_exact_tokens_for_tokens( - asset1: Coin, - asset2: Coin, + coin1: Coin, + coin2: Coin, amount: SubstrateAmount, include_fee: bool ) -> Option { - Dex::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) + Dex::quote_price_exact_tokens_for_tokens(coin1, coin2, amount, include_fee) } fn quote_price_tokens_for_exact_tokens( - asset1: Coin, - asset2: Coin, + coin1: Coin, + coin2: Coin, amount: SubstrateAmount, include_fee: bool ) -> Option { - Dex::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) + Dex::quote_price_tokens_for_exact_tokens(coin1, coin2, amount, include_fee) } - fn get_reserves(asset1: Coin, asset2: Coin) -> Option<(SubstrateAmount, SubstrateAmount)> { - Dex::get_reserves(&asset1, &asset2).ok() + fn get_reserves(coin1: Coin, coin2: Coin) -> Option<(SubstrateAmount, SubstrateAmount)> { + Dex::get_reserves(&coin1, &coin2).ok() } } } diff --git a/substrate/signals/primitives/src/lib.rs b/substrate/signals/primitives/src/lib.rs index cfd8aac56..c7f0565ac 100644 --- a/substrate/signals/primitives/src/lib.rs +++ b/substrate/signals/primitives/src/lib.rs @@ -5,7 +5,7 @@ use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; -use serai_primitives::NetworkId; +use serai_primitives::ExternalNetworkId; #[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(zeroize::Zeroize))] @@ -13,5 +13,5 @@ use serai_primitives::NetworkId; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum SignalId { Retirement([u8; 32]), - Halt(NetworkId), + Halt(ExternalNetworkId), } diff --git a/substrate/validator-sets/pallet/src/lib.rs b/substrate/validator-sets/pallet/src/lib.rs index c2ba80a96..383f94a7d 100644 --- a/substrate/validator-sets/pallet/src/lib.rs +++ b/substrate/validator-sets/pallet/src/lib.rs @@ -316,11 +316,13 @@ pub mod pallet { /// The generated key pair for a given validator set instance. #[pallet::storage] #[pallet::getter(fn keys)] - pub type Keys = StorageMap<_, Twox64Concat, ValidatorSet, KeyPair, OptionQuery>; + pub type Keys = + StorageMap<_, Twox64Concat, ExternalValidatorSet, KeyPair, OptionQuery>; /// The key for validator sets which can (and still need to) publish their slash reports. #[pallet::storage] - pub type PendingSlashReport = StorageMap<_, Identity, NetworkId, Public, OptionQuery>; + pub type PendingSlashReport = + StorageMap<_, Identity, ExternalNetworkId, Public, OptionQuery>; /// Disabled validators. #[pallet::storage] @@ -343,7 +345,7 @@ pub mod pallet { removed: T::AccountId, }, KeyGen { - set: ValidatorSet, + set: ExternalValidatorSet, key_pair: KeyPair, }, AcceptedHandover { @@ -600,14 +602,16 @@ pub mod pallet { amount: Amount, ) -> Result { // Check it's safe to decrease this set's stake by this amount - let new_total_staked = Self::total_allocated_stake(network) - .unwrap() - .0 - .checked_sub(amount.0) - .ok_or(Error::::NotEnoughAllocated)?; - let required_stake = Self::required_stake_for_network(network); - if new_total_staked < required_stake { - Err(Error::::DeallocationWouldRemoveEconomicSecurity)?; + if let NetworkId::External(n) = network { + let new_total_staked = Self::total_allocated_stake(NetworkId::from(n)) + .unwrap() + .0 + .checked_sub(amount.0) + .ok_or(Error::::NotEnoughAllocated)?; + let required_stake = Self::required_stake_for_network(n); + if new_total_staked < required_stake { + Err(Error::::DeallocationWouldRemoveEconomicSecurity)?; + } } let old_allocation = @@ -690,20 +694,23 @@ pub mod pallet { return false; } - // Handover is automatically complete for Serai as it doesn't have a handover protocol - if network == NetworkId::Serai { + let NetworkId::External(n) = network else { + // Handover is automatically complete for Serai as it doesn't have a handover protocol return true; - } + }; // The current session must have set keys for its handover to be completed - if !Keys::::contains_key(ValidatorSet { network, session }) { + if !Keys::::contains_key(ExternalValidatorSet { network: n, session }) { return false; } // This must be the first session (which has set keys) OR the prior session must have been // retired (signified by its keys no longer being present) (session.0 == 0) || - (!Keys::::contains_key(ValidatorSet { network, session: Session(session.0 - 1) })) + (!Keys::::contains_key(ExternalValidatorSet { + network: n, + session: Session(session.0 - 1), + })) } fn new_session() { @@ -733,19 +740,23 @@ pub mod pallet { // TODO: This is called retire_set, yet just starts retiring the set // Update the nomenclature within this function pub fn retire_set(set: ValidatorSet) { - // If the prior prior set didn't report, emit they're retired now - if PendingSlashReport::::get(set.network).is_some() { - Self::deposit_event(Event::SetRetired { - set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) }, - }); - } - // Serai doesn't set keys and network slashes are handled by BABE/GRANDPA - if set.network != NetworkId::Serai { + if let NetworkId::External(n) = set.network { + // If the prior prior set didn't report, emit they're retired now + if PendingSlashReport::::get(n).is_some() { + Self::deposit_event(Event::SetRetired { + set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) }, + }); + } + // This overwrites the prior value as the prior to-report set's stake presumably just // unlocked, making their report unenforceable - let keys = Keys::::take(set).unwrap(); - PendingSlashReport::::set(set.network, Some(keys.0)); + let keys = + Keys::::take(ExternalValidatorSet { network: n, session: set.session }).unwrap(); + PendingSlashReport::::set(n, Some(keys.0)); + } else { + // emit the event for serai network + Self::deposit_event(Event::SetRetired { set }); } // We're retiring this set because the set after it accepted the handover @@ -817,7 +828,7 @@ pub mod pallet { } /// Returns the required stake in terms SRI for a given `Balance`. - pub fn required_stake(balance: &Balance) -> SubstrateAmount { + pub fn required_stake(balance: &ExternalBalance) -> SubstrateAmount { use dex_pallet::HigherPrecisionBalance; // This is inclusive to an increase in accuracy @@ -840,11 +851,11 @@ pub mod pallet { } /// Returns the current total required stake for a given `network`. - pub fn required_stake_for_network(network: NetworkId) -> SubstrateAmount { + pub fn required_stake_for_network(network: ExternalNetworkId) -> SubstrateAmount { let mut total_required = 0; for coin in network.coins() { - let supply = Coins::::supply(coin); - total_required += Self::required_stake(&Balance { coin: *coin, amount: Amount(supply) }); + let supply = Coins::::supply(Coin::from(coin)); + total_required += Self::required_stake(&ExternalBalance { coin, amount: Amount(supply) }); } total_required } @@ -940,7 +951,7 @@ pub mod pallet { #[pallet::weight(0)] // TODO pub fn set_keys( origin: OriginFor, - network: NetworkId, + network: ExternalNetworkId, removed_participants: BoundedVec>, key_pair: KeyPair, signature: Signature, @@ -951,8 +962,8 @@ pub mod pallet { // (called by pre_dispatch) checks it let _ = signature; - let session = Self::session(network).unwrap(); - let set = ValidatorSet { network, session }; + let session = Self::session(NetworkId::from(network)).unwrap(); + let set = ExternalValidatorSet { network, session }; Keys::::set(set, Some(key_pair.clone())); @@ -960,7 +971,7 @@ pub mod pallet { // We generally set TotalAllocatedStake when the prior set retires, and the new set is fully // active and liable. Since this is the first set, there is no prior set to wait to retire if session == Session(0) { - Self::set_total_allocated_stake(network); + Self::set_total_allocated_stake(NetworkId::from(network)); } // This does not remove from TotalAllocatedStake or InSet in order to: @@ -970,7 +981,7 @@ pub mod pallet { // 2) Not allow parties removed to immediately deallocate, per commentary on deallocation // scheduling (https://github.com/serai-dex/serai/issues/394). for removed in removed_participants { - Self::deposit_event(Event::ParticipantRemoved { set, removed }); + Self::deposit_event(Event::ParticipantRemoved { set: set.into(), removed }); } Self::deposit_event(Event::KeyGen { set, key_pair }); @@ -981,7 +992,7 @@ pub mod pallet { #[pallet::weight(0)] // TODO pub fn report_slashes( origin: OriginFor, - network: NetworkId, + network: ExternalNetworkId, slashes: BoundedVec<(Public, u32), ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>, signature: Signature, ) -> DispatchResult { @@ -996,7 +1007,10 @@ pub mod pallet { // Emit set retireed Pallet::::deposit_event(Event::SetRetired { - set: ValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) }, + set: ValidatorSet { + network: network.into(), + session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1), + }, }); Ok(()) @@ -1062,17 +1076,12 @@ pub mod pallet { Call::set_keys { network, ref removed_participants, ref key_pair, ref signature } => { let network = *network; - // Don't allow the Serai set to set_keys, as they have no reason to do so - if network == NetworkId::Serai { - Err(InvalidTransaction::Custom(0))?; - } - // Confirm this set has a session - let Some(current_session) = Self::session(network) else { + let Some(current_session) = Self::session(NetworkId::from(network)) else { Err(InvalidTransaction::Custom(1))? }; - let set = ValidatorSet { network, session: current_session }; + let set = ExternalValidatorSet { network, session: current_session }; // Confirm it has yet to set keys if Keys::::get(set).is_some() { @@ -1081,7 +1090,7 @@ pub mod pallet { // This is a needed precondition as this uses storage variables for the latest decided // session on this assumption - assert_eq!(Pallet::::latest_decided_session(network), Some(current_session)); + assert_eq!(Pallet::::latest_decided_session(network.into()), Some(current_session)); // This does not slash the removed participants as that'll be done at the end of the // set's lifetime @@ -1094,15 +1103,15 @@ pub mod pallet { removed.insert(participant.0); } - let participants = - Participants::::get(network).expect("session existed without participants"); + let participants = Participants::::get(NetworkId::from(network)) + .expect("session existed without participants"); let mut all_key_shares = 0; let mut signers = vec![]; let mut signing_key_shares = 0; for participant in participants { let participant = participant.0; - let shares = InSet::::get(network, participant) + let shares = InSet::::get(NetworkId::from(network), participant) .expect("participant from Participants wasn't InSet"); all_key_shares += shares; @@ -1124,7 +1133,7 @@ pub mod pallet { // Verify the signature with the MuSig key of the signers // We theoretically don't need set_keys_message to bind to removed_participants, as the // key we're signing with effectively already does so, yet there's no reason not to - if !musig_key(set, &signers) + if !musig_key(set.into(), &signers) .verify(&set_keys_message(&set, removed_participants, key_pair), signature) { Err(InvalidTransaction::BadProof)?; @@ -1138,17 +1147,16 @@ pub mod pallet { } Call::report_slashes { network, ref slashes, ref signature } => { let network = *network; - // Don't allow Serai to publish a slash report as BABE/GRANDPA handles slashes directly - if network == NetworkId::Serai { - Err(InvalidTransaction::Custom(0))?; - } let Some(key) = PendingSlashReport::::take(network) else { // Assumed already published Err(InvalidTransaction::Stale)? }; + // There must have been a previous session is PendingSlashReport is populated - let set = - ValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) }; + let set = ExternalValidatorSet { + network, + session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1), + }; if !key.verify(&report_slashes_message(&set, slashes), signature) { Err(InvalidTransaction::BadProof)?; } @@ -1173,13 +1181,14 @@ pub mod pallet { } impl AllowMint for Pallet { - fn is_allowed(balance: &Balance) -> bool { + fn is_allowed(balance: &ExternalBalance) -> bool { // get the required stake let current_required = Self::required_stake_for_network(balance.coin.network()); let new_required = current_required + Self::required_stake(balance); // get the total stake for the network & compare. - let staked = Self::total_allocated_stake(balance.coin.network()).unwrap_or(Amount(0)); + let staked = + Self::total_allocated_stake(NetworkId::from(balance.coin.network())).unwrap_or(Amount(0)); staked.0 >= new_required } } diff --git a/substrate/validator-sets/primitives/src/lib.rs b/substrate/validator-sets/primitives/src/lib.rs index c900b0a99..9944d4852 100644 --- a/substrate/validator-sets/primitives/src/lib.rs +++ b/substrate/validator-sets/primitives/src/lib.rs @@ -17,7 +17,7 @@ use sp_core::{ConstU32, sr25519::Public, bounded::BoundedVec}; #[cfg(not(feature = "std"))] use sp_std::vec::Vec; -use serai_primitives::NetworkId; +use serai_primitives::{ExternalNetworkId, NetworkId}; /// The maximum amount of key shares per set. pub const MAX_KEY_SHARES_PER_SET: u32 = 150; @@ -43,6 +43,33 @@ pub struct ValidatorSet { pub network: NetworkId, } +/// The type used to identify a specific validator set during a specific session. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ExternalValidatorSet { + pub session: Session, + pub network: ExternalNetworkId, +} + +impl From for ValidatorSet { + fn from(set: ExternalValidatorSet) -> Self { + ValidatorSet { session: set.session, network: set.network.into() } + } +} + +impl TryFrom for ExternalValidatorSet { + type Error = (); + + fn try_from(set: ValidatorSet) -> Result { + match set.network { + NetworkId::Serai => Err(())?, + NetworkId::External(network) => Ok(ExternalValidatorSet { session: set.session, network }), + } + } +} + type MaxKeyLen = ConstU32; /// The type representing a Key from an external network. pub type ExternalKey = BoundedVec; @@ -100,14 +127,14 @@ pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public { /// The message for the set_keys signature. pub fn set_keys_message( - set: &ValidatorSet, + set: &ExternalValidatorSet, removed_participants: &[Public], key_pair: &KeyPair, ) -> Vec { (b"ValidatorSets-set_keys", set, removed_participants, key_pair).encode() } -pub fn report_slashes_message(set: &ValidatorSet, slashes: &[(Public, u32)]) -> Vec { +pub fn report_slashes_message(set: &ExternalValidatorSet, slashes: &[(Public, u32)]) -> Vec { (b"ValidatorSets-report_slashes", set, slashes).encode() } diff --git a/tests/coordinator/src/lib.rs b/tests/coordinator/src/lib.rs index c364128ca..a1efcf41c 100644 --- a/tests/coordinator/src/lib.rs +++ b/tests/coordinator/src/lib.rs @@ -19,7 +19,7 @@ use ciphersuite::{ Ciphersuite, Ristretto, }; -use serai_client::primitives::NetworkId; +use serai_client::primitives::ExternalNetworkId; use messages::{ coordinator::{SubstrateSignableId, SubstrateSignId, cosign_block_msg}, @@ -108,7 +108,7 @@ pub struct Handles { } pub struct Processor { - network: NetworkId, + network: ExternalNetworkId, serai_rpc: String, #[allow(unused)] @@ -132,7 +132,7 @@ impl Drop for Processor { impl Processor { pub async fn new( raw_i: u8, - network: NetworkId, + network: ExternalNetworkId, ops: &DockerOperations, handles: Handles, processor_key: ::F, diff --git a/tests/coordinator/src/tests/batch.rs b/tests/coordinator/src/tests/batch.rs index bfe4e36eb..4fb5e8583 100644 --- a/tests/coordinator/src/tests/batch.rs +++ b/tests/coordinator/src/tests/batch.rs @@ -16,7 +16,7 @@ use dkg::Participant; use scale::Encode; use serai_client::{ - primitives::{NetworkId, BlockHash, Signature}, + primitives::{BlockHash, Signature}, in_instructions::{ primitives::{Batch, SignedBatch, batch_message}, InInstructionsEvent, @@ -274,7 +274,7 @@ async fn batch_test() { Session(0), &substrate_key, Batch { - network: NetworkId::Bitcoin, + network: ExternalNetworkId::Bitcoin, id: 0, block: BlockHash([0x22; 32]), instructions: vec![], diff --git a/tests/coordinator/src/tests/key_gen.rs b/tests/coordinator/src/tests/key_gen.rs index 8ea14cbc0..66aa9f5bb 100644 --- a/tests/coordinator/src/tests/key_gen.rs +++ b/tests/coordinator/src/tests/key_gen.rs @@ -13,9 +13,8 @@ use ciphersuite::{ use dkg::ThresholdParams; use serai_client::{ - primitives::NetworkId, + validator_sets::primitives::{ExternalValidatorSet, KeyPair, Session}, Public, - validator_sets::primitives::{Session, ValidatorSet, KeyPair}, }; use messages::{key_gen::KeyGenId, CoordinatorMessage}; @@ -28,7 +27,7 @@ pub async fn key_gen( let coordinators = processors.len(); let mut participant_is = vec![]; - let set = ValidatorSet { session, network: NetworkId::Bitcoin }; + let set = ExternalValidatorSet { session, network: ExternalNetworkId::Bitcoin }; let id = KeyGenId { session: set.session, attempt: 0 }; for (i, processor) in processors.iter_mut().enumerate() { diff --git a/tests/coordinator/src/tests/mod.rs b/tests/coordinator/src/tests/mod.rs index ef67b0ac5..a488d01ad 100644 --- a/tests/coordinator/src/tests/mod.rs +++ b/tests/coordinator/src/tests/mod.rs @@ -104,7 +104,7 @@ pub(crate) async fn new_test(test_body: impl TestBody, fast_epoch: bool) { handles.insert(name, handle); } - let processor_key = message_queue_keys[&NetworkId::Bitcoin]; + let processor_key = message_queue_keys[&ExternalNetworkId::Bitcoin]; coordinators.push(( Handles { @@ -198,7 +198,7 @@ pub(crate) async fn new_test(test_body: impl TestBody, fast_epoch: bool) { processors.push( Processor::new( i.try_into().unwrap(), - NetworkId::Bitcoin, + ExternalNetworkId::Bitcoin, &outer_ops, handles.clone(), *key, diff --git a/tests/coordinator/src/tests/rotation.rs b/tests/coordinator/src/tests/rotation.rs index 1ebeec16a..c3659a9e2 100644 --- a/tests/coordinator/src/tests/rotation.rs +++ b/tests/coordinator/src/tests/rotation.rs @@ -132,13 +132,13 @@ async fn set_rotation_test() { // excluded participant let pair5 = insecure_pair_from_name("Eve"); - let network = NetworkId::Bitcoin; + let network = ExternalNetworkId::Bitcoin; let amount = Amount(1_000_000 * 10_u64.pow(8)); let serai = processors[0].serai().await; // allocate now for the last participant so that it is guaranteed to be included into session // 1 set. This doesn't affect the genesis set at all since that is a predetermined set. - allocate_stake(&serai, network, amount, &pair5, 0).await; + allocate_stake(&serai, network.into(), amount, &pair5, 0).await; // genesis keygen let _ = key_gen::(&mut processors, Session(0)).await; @@ -151,12 +151,14 @@ async fn set_rotation_test() { } // wait until next session to see the effect on coordinator - wait_till_session_1(&serai, network).await; + wait_till_session_1(&serai, network.into()).await; // Ensure the new validator was included in the new set assert_eq!( - most_recent_new_set_event(&serai, network).await, - ValidatorSetsEvent::NewSet { set: ValidatorSet { session: Session(1), network } }, + most_recent_new_set_event(&serai, network.into()).await, + ValidatorSetsEvent::NewSet { + set: ValidatorSet { session: Session(1), network: network.into() } + }, ); // add the last participant & do the keygen diff --git a/tests/coordinator/src/tests/sign.rs b/tests/coordinator/src/tests/sign.rs index db8a72034..f6fdb6e6e 100644 --- a/tests/coordinator/src/tests/sign.rs +++ b/tests/coordinator/src/tests/sign.rs @@ -10,18 +10,17 @@ use ciphersuite::Secp256k1; use dkg::Participant; use serai_client::{ - PairTrait, - primitives::{ - NetworkId, Coin, Amount, Balance, BlockHash, SeraiAddress, ExternalAddress, - insecure_pair_from_name, - }, coins::{ primitives::{OutInstruction, OutInstructionWithBalance}, CoinsEvent, }, - in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch}, + in_instructions::primitives::{Batch, InInstruction, InInstructionWithBalance}, + primitives::{ + insecure_pair_from_name, Amount, Balance, BlockHash, Coin, ExternalAddress, ExternalBalance, + ExternalCoin, SeraiAddress, + }, validator_sets::primitives::Session, - SeraiCoins, + PairTrait, SeraiCoins, }; use messages::{coordinator::PlanMeta, sign::SignId, SubstrateContext, CoordinatorMessage}; @@ -202,7 +201,7 @@ async fn sign_test() { #[allow(clippy::inconsistent_digit_grouping)] let amount = Amount(1_000_000_00); - let balance = Balance { coin: Coin::Bitcoin, amount }; + let balance = ExternalBalance { coin: ExternalCoin::Bitcoin, amount }; let coin_block = BlockHash([0x33; 32]); let block_included_in = batch( @@ -211,7 +210,7 @@ async fn sign_test() { Session(0), &substrate_key, Batch { - network: NetworkId::Bitcoin, + network: balance.coin.network(), id: 0, block: coin_block, instructions: vec![InInstructionWithBalance { @@ -236,10 +235,13 @@ async fn sign_test() { // Verify the mint occurred as expected assert_eq!( serai.mint_events().await.unwrap(), - vec![CoinsEvent::Mint { to: serai_addr, balance }] + vec![CoinsEvent::Mint { to: serai_addr, balance: balance.into() }] + ); + assert_eq!(serai.coin_supply(ExternalCoin::Bitcoin.into()).await.unwrap(), amount); + assert_eq!( + serai.coin_balance(ExternalCoin::Bitcoin.into(), serai_addr).await.unwrap(), + amount ); - assert_eq!(serai.coin_supply(Coin::Bitcoin).await.unwrap(), amount); - assert_eq!(serai.coin_balance(Coin::Bitcoin, serai_addr).await.unwrap(), amount); } // Trigger a burn @@ -296,8 +298,11 @@ async fn sign_test() { let last_serai_block_hash = last_serai_block.hash(); let serai = serai.as_of(last_serai_block_hash); let serai = serai.coins(); - assert_eq!(serai.coin_supply(Coin::Bitcoin).await.unwrap(), Amount(0)); - assert_eq!(serai.coin_balance(Coin::Bitcoin, serai_addr).await.unwrap(), Amount(0)); + assert_eq!(serai.coin_supply(ExternalCoin::Bitcoin.into()).await.unwrap(), Amount(0)); + assert_eq!( + serai.coin_balance(ExternalCoin::Bitcoin.into(), serai_addr).await.unwrap(), + Amount(0) + ); let mut plan_id = [0; 32]; OsRng.fill_bytes(&mut plan_id); diff --git a/tests/full-stack/src/tests/mint_and_burn.rs b/tests/full-stack/src/tests/mint_and_burn.rs index ce19808fd..26ffb442c 100644 --- a/tests/full-stack/src/tests/mint_and_burn.rs +++ b/tests/full-stack/src/tests/mint_and_burn.rs @@ -9,12 +9,13 @@ use rand_core::{RngCore, OsRng}; use scale::Encode; use serai_client::{ + coins::primitives::{OutInstruction, OutInstructionWithBalance}, + in_instructions::primitives::Shorthand, primitives::{ - NetworkId, Coin, Amount, Balance, SeraiAddress, ExternalAddress, insecure_pair_from_name, + insecure_pair_from_name, Amount, Balance, Coin, ExternalAddress, ExternalBalance, ExternalCoin, + SeraiAddress, }, - validator_sets::primitives::{Session, ValidatorSet}, - in_instructions::primitives::Shorthand, - coins::primitives::{OutInstruction, OutInstructionWithBalance}, + validator_sets::primitives::{ExternalValidatorSet, Session}, PairTrait, SeraiCoins, }; @@ -199,7 +200,7 @@ async fn mint_and_burn_test() { .await .unwrap() .validator_sets() - .keys(ValidatorSet { network, session: Session(0) }) + .keys(ExternalValidatorSet { network, session: Session(0) }) .await .unwrap() { @@ -224,7 +225,10 @@ async fn mint_and_burn_test() { } }; - (key_pair(false, NetworkId::Bitcoin).await, key_pair(true, NetworkId::Monero).await) + ( + key_pair(false, ExternalNetworkId::Bitcoin).await, + key_pair(true, ExternalNetworkId::Monero).await, + ) }; // Because the initial keys only become active when the network's time matches the Serai @@ -439,8 +443,8 @@ async fn mint_and_burn_test() { ); } }; - wait_for_batch(false, NetworkId::Bitcoin).await; - wait_for_batch(true, NetworkId::Monero).await; + wait_for_batch(false, ExternalNetworkId::Bitcoin).await; + wait_for_batch(true, ExternalNetworkId::Monero).await; } // TODO: Verify the mints @@ -492,7 +496,7 @@ async fn mint_and_burn_test() { let serai_pair = &serai_pair; move |nonce, coin, amount, address| async move { let out_instruction = OutInstructionWithBalance { - balance: Balance { coin, amount: Amount(amount) }, + balance: ExternalBalance { coin, amount: Amount(amount) }, instruction: OutInstruction { address, data: None }, }; @@ -511,7 +515,7 @@ async fn mint_and_burn_test() { #[allow(clippy::inconsistent_digit_grouping)] burn( 0, - Coin::Bitcoin, + ExternalCoin::Bitcoin, 1_000_000_00, ExternalAddress::new( serai_client::networks::bitcoin::Address::new(bitcoin_addr.clone()).unwrap().into(), @@ -522,7 +526,7 @@ async fn mint_and_burn_test() { burn( 1, - Coin::Monero, + ExternalCoin::Monero, 1_000_000_000_000, ExternalAddress::new( serai_client::networks::monero::Address::new(monero_addr).unwrap().into(), diff --git a/tests/full-stack/src/tests/mod.rs b/tests/full-stack/src/tests/mod.rs index 7d92070ef..b82ff177e 100644 --- a/tests/full-stack/src/tests/mod.rs +++ b/tests/full-stack/src/tests/mod.rs @@ -3,7 +3,7 @@ use std::{sync::OnceLock, collections::HashMap}; use tokio::sync::Mutex; -use serai_client::primitives::NetworkId; +use serai_client::primitives::ExternalNetworkId; use dockertest::{ LogAction, LogPolicy, LogSource, LogOptions, StartPolicy, TestBodySpecification, @@ -56,15 +56,21 @@ pub(crate) async fn new_test(test_body: impl TestBody) { let (coord_key, message_queue_keys, message_queue_composition) = message_queue_instance(); - let (bitcoin_composition, bitcoin_port) = network_instance(NetworkId::Bitcoin); - let mut bitcoin_processor_composition = - processor_instance(NetworkId::Bitcoin, bitcoin_port, message_queue_keys[&NetworkId::Bitcoin]); + let (bitcoin_composition, bitcoin_port) = network_instance(ExternalNetworkId::Bitcoin); + let mut bitcoin_processor_composition = processor_instance( + ExternalNetworkId::Bitcoin, + bitcoin_port, + message_queue_keys[&ExternalNetworkId::Bitcoin], + ); assert_eq!(bitcoin_processor_composition.len(), 1); let bitcoin_processor_composition = bitcoin_processor_composition.swap_remove(0); - let (monero_composition, monero_port) = network_instance(NetworkId::Monero); - let mut monero_processor_composition = - processor_instance(NetworkId::Monero, monero_port, message_queue_keys[&NetworkId::Monero]); + let (monero_composition, monero_port) = network_instance(ExternalNetworkId::Monero); + let mut monero_processor_composition = processor_instance( + ExternalNetworkId::Monero, + monero_port, + message_queue_keys[&ExternalNetworkId::Monero], + ); assert_eq!(monero_processor_composition.len(), 1); let monero_processor_composition = monero_processor_composition.swap_remove(0); diff --git a/tests/message-queue/src/lib.rs b/tests/message-queue/src/lib.rs index e2bfd3a75..d59273d95 100644 --- a/tests/message-queue/src/lib.rs +++ b/tests/message-queue/src/lib.rs @@ -7,23 +7,25 @@ use ciphersuite::{ Ciphersuite, Ristretto, }; -use serai_primitives::NetworkId; +use serai_primitives::{ExternalNetworkId, EXTERNAL_NETWORKS}; use dockertest::{ PullPolicy, Image, LogAction, LogPolicy, LogSource, LogOptions, TestBodySpecification, }; pub type MessageQueuePrivateKey = ::F; -pub fn instance( -) -> (MessageQueuePrivateKey, HashMap, TestBodySpecification) { +pub fn instance() -> ( + MessageQueuePrivateKey, + HashMap, + TestBodySpecification, +) { serai_docker_tests::build("message-queue".to_string()); let coord_key = ::F::random(&mut OsRng); - let priv_keys = HashMap::from([ - (NetworkId::Bitcoin, ::F::random(&mut OsRng)), - (NetworkId::Ethereum, ::F::random(&mut OsRng)), - (NetworkId::Monero, ::F::random(&mut OsRng)), - ]); + let priv_keys = EXTERNAL_NETWORKS + .into_iter() + .map(|n| (n, ::F::random(&mut OsRng))) + .collect::>(); let composition = TestBodySpecification::with_image( Image::with_repository("serai-dev-message-queue").pull_policy(PullPolicy::Never), @@ -38,15 +40,15 @@ pub fn instance( ("COORDINATOR_KEY".to_string(), hex::encode((Ristretto::generator() * coord_key).to_bytes())), ( "BITCOIN_KEY".to_string(), - hex::encode((Ristretto::generator() * priv_keys[&NetworkId::Bitcoin]).to_bytes()), + hex::encode((Ristretto::generator() * priv_keys[&ExternalNetworkId::Bitcoin]).to_bytes()), ), ( "ETHEREUM_KEY".to_string(), - hex::encode((Ristretto::generator() * priv_keys[&NetworkId::Ethereum]).to_bytes()), + hex::encode((Ristretto::generator() * priv_keys[&ExternalNetworkId::Ethereum]).to_bytes()), ), ( "MONERO_KEY".to_string(), - hex::encode((Ristretto::generator() * priv_keys[&NetworkId::Monero]).to_bytes()), + hex::encode((Ristretto::generator() * priv_keys[&ExternalNetworkId::Monero]).to_bytes()), ), ("DB_PATH".to_string(), "./message-queue-db".to_string()), ("RUST_LOG".to_string(), "serai_message_queue=trace,".to_string()), @@ -85,7 +87,7 @@ fn basic_functionality() { .queue( Metadata { from: Service::Coordinator, - to: Service::Processor(NetworkId::Bitcoin), + to: Service::Processor(ExternalNetworkId::Bitcoin), intent: b"intent".to_vec(), }, b"Hello, World!".to_vec(), @@ -98,7 +100,7 @@ fn basic_functionality() { .queue( Metadata { from: Service::Coordinator, - to: Service::Processor(NetworkId::Bitcoin), + to: Service::Processor(ExternalNetworkId::Bitcoin), intent: b"intent 2".to_vec(), }, b"Hello, World, again!".to_vec(), @@ -108,9 +110,9 @@ fn basic_functionality() { // Successfully get it let bitcoin = MessageQueue::new( - Service::Processor(NetworkId::Bitcoin), + Service::Processor(ExternalNetworkId::Bitcoin), rpc.clone(), - Zeroizing::new(priv_keys[&NetworkId::Bitcoin]), + Zeroizing::new(priv_keys[&ExternalNetworkId::Bitcoin]), ); let msg = bitcoin.next(Service::Coordinator).await; assert_eq!(msg.from, Service::Coordinator); @@ -140,7 +142,7 @@ fn basic_functionality() { .queue( Metadata { from: Service::Coordinator, - to: Service::Processor(NetworkId::Monero), + to: Service::Processor(ExternalNetworkId::Monero), // Intents should be per-from-to, making this valid intent: b"intent".to_vec(), }, @@ -149,9 +151,9 @@ fn basic_functionality() { .await; let monero = MessageQueue::new( - Service::Processor(NetworkId::Monero), + Service::Processor(ExternalNetworkId::Monero), rpc, - Zeroizing::new(priv_keys[&NetworkId::Monero]), + Zeroizing::new(priv_keys[&ExternalNetworkId::Monero]), ); assert_eq!(monero.next(Service::Coordinator).await.id, 0); monero.ack(Service::Coordinator, 0).await; diff --git a/tests/processor/src/lib.rs b/tests/processor/src/lib.rs index ec607a551..571916fd4 100644 --- a/tests/processor/src/lib.rs +++ b/tests/processor/src/lib.rs @@ -7,7 +7,7 @@ use rand_core::{RngCore, OsRng}; use ciphersuite::{group::ff::PrimeField, Ciphersuite, Ristretto}; -use serai_client::primitives::NetworkId; +use serai_client::primitives::ExternalNetworkId; use messages::{ProcessorMessage, CoordinatorMessage}; use serai_message_queue::{Service, Metadata, client::MessageQueue}; @@ -25,7 +25,7 @@ mod tests; static UNIQUE_ID: OnceLock> = OnceLock::new(); pub fn processor_instance( - network: NetworkId, + network: ExternalNetworkId, port: u32, message_queue_key: ::F, ) -> Vec { @@ -33,10 +33,9 @@ pub fn processor_instance( OsRng.fill_bytes(&mut entropy); let network_str = match network { - NetworkId::Serai => panic!("starting a processor for Serai"), - NetworkId::Bitcoin => "bitcoin", - NetworkId::Ethereum => "ethereum", - NetworkId::Monero => "monero", + ExternalNetworkId::Bitcoin => "bitcoin", + ExternalNetworkId::Ethereum => "ethereum", + ExternalNetworkId::Monero => "monero", }; let image = format!("{network_str}-processor"); serai_docker_tests::build(image.clone()); @@ -57,7 +56,7 @@ pub fn processor_instance( .into(), )]; - if network == NetworkId::Ethereum { + if network == ExternalNetworkId::Ethereum { serai_docker_tests::build("ethereum-relayer".to_string()); res.push( TestBodySpecification::with_image( @@ -80,7 +79,7 @@ pub fn processor_instance( pub type Handles = (String, String, String, String); pub fn processor_stack( - network: NetworkId, + network: ExternalNetworkId, network_hostname_override: Option, ) -> (Handles, ::F, Vec) { let (network_composition, network_rpc_port) = network_instance(network); @@ -106,10 +105,9 @@ pub fn processor_stack( for (name, composition) in [ Some(( match network { - NetworkId::Serai => unreachable!(), - NetworkId::Bitcoin => "bitcoin", - NetworkId::Ethereum => "ethereum", - NetworkId::Monero => "monero", + ExternalNetworkId::Bitcoin => "bitcoin", + ExternalNetworkId::Ethereum => "ethereum", + ExternalNetworkId::Monero => "monero", }, network_composition, )), @@ -161,7 +159,7 @@ pub fn processor_stack( } pub struct Coordinator { - network: NetworkId, + network: ExternalNetworkId, network_handle: String, #[allow(unused)] @@ -177,7 +175,7 @@ pub struct Coordinator { impl Coordinator { pub fn new( - network: NetworkId, + network: ExternalNetworkId, ops: &DockerOperations, handles: Handles, coord_key: ::F, @@ -213,7 +211,7 @@ impl Coordinator { let mut iters = 0; while iters < 60 { match network { - NetworkId::Bitcoin => { + ExternalNetworkId::Bitcoin => { use bitcoin_serai::rpc::Rpc; // Bitcoin's Rpc::new will test the connection @@ -221,7 +219,7 @@ impl Coordinator { break; } } - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { use std::sync::Arc; use ethereum_serai::{ alloy::{ @@ -270,7 +268,7 @@ impl Coordinator { break; } } - NetworkId::Monero => { + ExternalNetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::rpc::Rpc; @@ -284,7 +282,6 @@ impl Coordinator { break; } } - NetworkId::Serai => panic!("processor is booting with external network of Serai"), } println!("external network RPC has yet to boot, waiting 1 sec, attempt {iters}"); @@ -337,7 +334,7 @@ impl Coordinator { pub async fn add_block(&self, ops: &DockerOperations) -> ([u8; 32], Vec) { let rpc_url = network_rpc(self.network, ops, &self.network_handle); match self.network { - NetworkId::Bitcoin => { + ExternalNetworkId::Bitcoin => { use bitcoin_serai::{ bitcoin::{consensus::Encodable, network::Network, Script, Address}, rpc::Rpc, @@ -360,7 +357,7 @@ impl Coordinator { block.consensus_encode(&mut block_buf).unwrap(); (hash, block_buf) } - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { use ethereum_serai::alloy::{ simple_request_transport::SimpleRequest, rpc_types::{BlockTransactionsKind, BlockNumberOrTag}, @@ -397,7 +394,7 @@ impl Coordinator { .into_bytes(); (hash.into(), state) } - NetworkId::Monero => { + ExternalNetworkId::Monero => { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{rpc::Rpc, address::Network, ViewPair}; @@ -415,14 +412,13 @@ impl Coordinator { let hash = rpc.get_block_hash(rpc.get_height().await.unwrap() - 1).await.unwrap(); (hash, rpc.get_block(hash).await.unwrap().serialize()) } - NetworkId::Serai => panic!("processor tests adding block to Serai"), } } pub async fn sync(&self, ops: &DockerOperations, others: &[Coordinator]) { let rpc_url = network_rpc(self.network, ops, &self.network_handle); match self.network { - NetworkId::Bitcoin => { + ExternalNetworkId::Bitcoin => { use bitcoin_serai::{bitcoin::consensus::Encodable, rpc::Rpc}; let rpc = Rpc::new(rpc_url).await.expect("couldn't connect to the Bitcoin RPC"); @@ -452,7 +448,7 @@ impl Coordinator { } } } - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { use ethereum_serai::alloy::{ simple_request_transport::SimpleRequest, rpc_types::{BlockTransactionsKind, BlockNumberOrTag}, @@ -503,7 +499,7 @@ impl Coordinator { //assert_eq!(expected_number, new_number); } } - NetworkId::Monero => { + ExternalNetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::rpc::Rpc; @@ -534,14 +530,13 @@ impl Coordinator { } } } - NetworkId::Serai => panic!("processors tests syncing Serai nodes"), } } pub async fn publish_transaction(&self, ops: &DockerOperations, tx: &[u8]) { let rpc_url = network_rpc(self.network, ops, &self.network_handle); match self.network { - NetworkId::Bitcoin => { + ExternalNetworkId::Bitcoin => { use bitcoin_serai::{ bitcoin::{consensus::Decodable, Transaction}, rpc::Rpc, @@ -551,7 +546,7 @@ impl Coordinator { Rpc::new(rpc_url).await.expect("couldn't connect to the coordinator's Bitcoin RPC"); rpc.send_raw_transaction(&Transaction::consensus_decode(&mut &*tx).unwrap()).await.unwrap(); } - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { use ethereum_serai::alloy::{ simple_request_transport::SimpleRequest, rpc_client::ClientBuilder, @@ -564,7 +559,7 @@ impl Coordinator { ); let _ = provider.send_raw_transaction(tx).await.unwrap(); } - NetworkId::Monero => { + ExternalNetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{transaction::Transaction, rpc::Rpc}; @@ -573,15 +568,15 @@ impl Coordinator { .expect("couldn't connect to the coordinator's Monero RPC"); rpc.publish_transaction(&Transaction::read(&mut &*tx).unwrap()).await.unwrap(); } - NetworkId::Serai => panic!("processor tests broadcasting block to Serai"), } } pub async fn publish_eventuality_completion(&self, ops: &DockerOperations, tx: &[u8]) { match self.network { - NetworkId::Bitcoin | NetworkId::Monero => self.publish_transaction(ops, tx).await, - NetworkId::Ethereum => (), - NetworkId::Serai => panic!("processor tests broadcasting block to Serai"), + ExternalNetworkId::Bitcoin | ExternalNetworkId::Monero => { + self.publish_transaction(ops, tx).await + } + ExternalNetworkId::Ethereum => (), } } @@ -592,7 +587,7 @@ impl Coordinator { ) -> Option> { let rpc_url = network_rpc(self.network, ops, &self.network_handle); match self.network { - NetworkId::Bitcoin => { + ExternalNetworkId::Bitcoin => { use bitcoin_serai::{bitcoin::consensus::Encodable, rpc::Rpc}; let rpc = @@ -614,7 +609,7 @@ impl Coordinator { None } } - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { /* let provider = RootProvider::<_, Ethereum>::new( ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true), @@ -664,7 +659,7 @@ impl Coordinator { None } - NetworkId::Monero => { + ExternalNetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::rpc::Rpc; @@ -679,7 +674,6 @@ impl Coordinator { None } } - NetworkId::Serai => panic!("processor tests broadcasting block to Serai"), } } } diff --git a/tests/processor/src/networks.rs b/tests/processor/src/networks.rs index 32563c9fe..f2cc4e862 100644 --- a/tests/processor/src/networks.rs +++ b/tests/processor/src/networks.rs @@ -4,9 +4,9 @@ use rand_core::{RngCore, OsRng}; use scale::Encode; use serai_client::{ - primitives::{Amount, NetworkId, Coin, Balance, ExternalAddress}, - validator_sets::primitives::ExternalKey, in_instructions::primitives::{InInstruction, RefundableInInstruction, Shorthand}, + primitives::{Amount, ExternalAddress, ExternalBalance, ExternalCoin, ExternalNetworkId}, + validator_sets::primitives::ExternalKey, }; use dockertest::{PullPolicy, Image, StartPolicy, TestBodySpecification, DockerOperations}; @@ -52,37 +52,32 @@ pub fn monero_instance() -> (TestBodySpecification, u32) { (composition, XMR_PORT) } -pub fn network_instance(network: NetworkId) -> (TestBodySpecification, u32) { +pub fn network_instance(network: ExternalNetworkId) -> (TestBodySpecification, u32) { match network { - NetworkId::Bitcoin => bitcoin_instance(), - NetworkId::Ethereum => ethereum_instance(), - NetworkId::Monero => monero_instance(), - NetworkId::Serai => { - panic!("Serai is not a valid network to spawn an instance of for a processor") - } + ExternalNetworkId::Bitcoin => bitcoin_instance(), + ExternalNetworkId::Ethereum => ethereum_instance(), + ExternalNetworkId::Monero => monero_instance(), } } -pub fn network_rpc(network: NetworkId, ops: &DockerOperations, handle: &str) -> String { +pub fn network_rpc(network: ExternalNetworkId, ops: &DockerOperations, handle: &str) -> String { let (ip, port) = ops .handle(handle) .host_port(match network { - NetworkId::Bitcoin => BTC_PORT, - NetworkId::Ethereum => ETH_PORT, - NetworkId::Monero => XMR_PORT, - NetworkId::Serai => panic!("getting port for external network yet it was Serai"), + ExternalNetworkId::Bitcoin => BTC_PORT, + ExternalNetworkId::Ethereum => ETH_PORT, + ExternalNetworkId::Monero => XMR_PORT, }) .unwrap(); format!("http://{RPC_USER}:{RPC_PASS}@{ip}:{port}") } -pub fn confirmations(network: NetworkId) -> usize { +pub fn confirmations(network: ExternalNetworkId) -> usize { use processor::networks::*; match network { - NetworkId::Bitcoin => Bitcoin::CONFIRMATIONS, - NetworkId::Ethereum => Ethereum::::CONFIRMATIONS, - NetworkId::Monero => Monero::CONFIRMATIONS, - NetworkId::Serai => panic!("getting confirmations required for Serai"), + ExternalNetworkId::Bitcoin => Bitcoin::CONFIRMATIONS, + ExternalNetworkId::Ethereum => Ethereum::::CONFIRMATIONS, + ExternalNetworkId::Monero => Monero::CONFIRMATIONS, } } @@ -108,11 +103,11 @@ pub enum Wallet { // TODO: Merge these functions with the processor's tests, which offers very similar functionality impl Wallet { - pub async fn new(network: NetworkId, ops: &DockerOperations, handle: String) -> Wallet { + pub async fn new(network: ExternalNetworkId, ops: &DockerOperations, handle: String) -> Wallet { let rpc_url = network_rpc(network, ops, &handle); match network { - NetworkId::Bitcoin => { + ExternalNetworkId::Bitcoin => { use bitcoin_serai::{ bitcoin::{ secp256k1::{SECP256K1, SecretKey}, @@ -153,7 +148,7 @@ impl Wallet { Wallet::Bitcoin { private_key, public_key, input_tx: funds } } - NetworkId::Ethereum => { + ExternalNetworkId::Ethereum => { use ciphersuite::{group::ff::Field, Secp256k1}; use ethereum_serai::alloy::{ primitives::{U256, Address}, @@ -185,7 +180,7 @@ impl Wallet { Wallet::Ethereum { rpc_url: rpc_url.clone(), key, nonce: 0 } } - NetworkId::Monero => { + ExternalNetworkId::Monero => { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{rpc::Rpc, address::Network, ViewPair}; @@ -210,7 +205,6 @@ impl Wallet { last_tx: (height, block.miner_transaction.hash()), } } - NetworkId::Serai => panic!("creating a wallet for for Serai"), } } @@ -219,7 +213,7 @@ impl Wallet { ops: &DockerOperations, to: &ExternalKey, instruction: Option, - ) -> (Vec, Balance) { + ) -> (Vec, ExternalBalance) { match self { Wallet::Bitcoin { private_key, public_key, ref mut input_tx } => { use bitcoin_serai::bitcoin::{ @@ -298,7 +292,7 @@ impl Wallet { let mut buf = vec![]; tx.consensus_encode(&mut buf).unwrap(); *input_tx = tx; - (buf, Balance { coin: Coin::Bitcoin, amount: Amount(AMOUNT) }) + (buf, ExternalBalance { coin: ExternalCoin::Bitcoin, amount: Amount(AMOUNT) }) } Wallet::Ethereum { rpc_url, key, ref mut nonce } => { @@ -400,7 +394,10 @@ impl Wallet { // We drop the bottom 10 decimals ( bytes, - Balance { coin: Coin::Ether, amount: Amount(u64::try_from(eight_decimals).unwrap()) }, + ExternalBalance { + coin: ExternalCoin::Ether, + amount: Amount(u64::try_from(eight_decimals).unwrap()), + }, ) } @@ -417,7 +414,7 @@ impl Wallet { }; use processor::{additional_key, networks::Monero}; - let rpc_url = network_rpc(NetworkId::Monero, ops, handle); + let rpc_url = network_rpc(ExternalNetworkId::Monero, ops, handle); let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); // Prepare inputs @@ -485,7 +482,7 @@ impl Wallet { last_tx.0 = current_height; last_tx.1 = tx.hash(); - (tx.serialize(), Balance { coin: Coin::Monero, amount: Amount(AMOUNT) }) + (tx.serialize(), ExternalBalance { coin: ExternalCoin::Monero, amount: Amount(AMOUNT) }) } } } diff --git a/tests/processor/src/tests/batch.rs b/tests/processor/src/tests/batch.rs index 6170270ac..4a34500ea 100644 --- a/tests/processor/src/tests/batch.rs +++ b/tests/processor/src/tests/batch.rs @@ -8,11 +8,12 @@ use dkg::{Participant, tests::clone_without}; use messages::{coordinator::*, SubstrateContext}; use serai_client::{ - primitives::{ - BlockHash, Amount, Balance, crypto::RuntimePublic, PublicKey, SeraiAddress, NetworkId, - }, in_instructions::primitives::{ - InInstruction, InInstructionWithBalance, Batch, SignedBatch, batch_message, + batch_message, Batch, InInstruction, InInstructionWithBalance, SignedBatch, + }, + primitives::{ + crypto::RuntimePublic, Amount, BlockHash, ExternalBalance, ExternalNetworkId, PublicKey, + SeraiAddress, EXTERNAL_NETWORKS, }, validator_sets::primitives::Session, }; @@ -189,7 +190,7 @@ pub(crate) async fn substrate_block( #[test] fn batch_test() { - for network in [NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero] { + for network in EXTERNAL_NETWORKS { let (coordinators, test) = new_test(network); test.run(|ops| async move { @@ -255,15 +256,14 @@ fn batch_test() { instructions: if let Some(instruction) = &instruction { vec![InInstructionWithBalance { instruction: instruction.clone(), - balance: Balance { + balance: ExternalBalance { coin: balance_sent.coin, amount: Amount( balance_sent.amount.0 - (2 * match network { - NetworkId::Bitcoin => Bitcoin::COST_TO_AGGREGATE, - NetworkId::Ethereum => Ethereum::::COST_TO_AGGREGATE, - NetworkId::Monero => Monero::COST_TO_AGGREGATE, - NetworkId::Serai => panic!("minted for Serai?"), + ExternalNetworkId::Bitcoin => Bitcoin::COST_TO_AGGREGATE, + ExternalNetworkId::Ethereum => Ethereum::::COST_TO_AGGREGATE, + ExternalNetworkId::Monero => Monero::COST_TO_AGGREGATE, }), ), }, @@ -322,7 +322,9 @@ fn batch_test() { }, ) .await; - if instruction.is_some() || (instruction.is_none() && (network == NetworkId::Monero)) { + if instruction.is_some() || + (instruction.is_none() && (network == ExternalNetworkId::Monero)) + { assert!(plans.is_empty()); } else { // If no instruction was used, and the processor csn presume the origin, it'd have @@ -335,7 +337,7 @@ fn batch_test() { // With the latter InInstruction not existing, we should've triggered a refund if the origin // was detectable // Check this is trying to sign a Plan - if network != NetworkId::Monero { + if network != ExternalNetworkId::Monero { let mut refund_id = None; for coordinator in &mut coordinators { match coordinator.recv_message().await { diff --git a/tests/processor/src/tests/key_gen.rs b/tests/processor/src/tests/key_gen.rs index 7dea0bfd5..ec616b514 100644 --- a/tests/processor/src/tests/key_gen.rs +++ b/tests/processor/src/tests/key_gen.rs @@ -3,8 +3,8 @@ use std::{collections::HashMap, time::SystemTime}; use dkg::{Participant, ThresholdParams, tests::clone_without}; use serai_client::{ - primitives::{NetworkId, BlockHash, PublicKey}, - validator_sets::primitives::{Session, KeyPair}, + primitives::{BlockHash, PublicKey, EXTERNAL_NETWORKS}, + validator_sets::primitives::{KeyPair, Session}, }; use messages::{SubstrateContext, key_gen::KeyGenId, CoordinatorMessage, ProcessorMessage}; @@ -144,7 +144,7 @@ pub(crate) async fn key_gen(coordinators: &mut [Coordinator]) -> KeyPair { #[test] fn key_gen_test() { - for network in [NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero] { + for network in EXTERNAL_NETWORKS { let (coordinators, test) = new_test(network); test.run(|ops| async move { diff --git a/tests/processor/src/tests/mod.rs b/tests/processor/src/tests/mod.rs index afda97d5e..0347a3dd0 100644 --- a/tests/processor/src/tests/mod.rs +++ b/tests/processor/src/tests/mod.rs @@ -1,7 +1,5 @@ use ciphersuite::{Ciphersuite, Ristretto}; -use serai_client::primitives::NetworkId; - use dockertest::DockerTest; use crate::*; @@ -17,7 +15,9 @@ mod send; pub(crate) const COORDINATORS: usize = 4; pub(crate) const THRESHOLD: usize = ((COORDINATORS * 2) / 3) + 1; -fn new_test(network: NetworkId) -> (Vec<(Handles, ::F)>, DockerTest) { +fn new_test( + network: ExternalNetworkId, +) -> (Vec<(Handles, ::F)>, DockerTest) { let mut coordinators = vec![]; let mut test = DockerTest::new().with_network(dockertest::Network::Isolated); let mut eth_handle = None; @@ -25,7 +25,7 @@ fn new_test(network: NetworkId) -> (Vec<(Handles, ::F) let (handles, coord_key, compositions) = processor_stack(network, eth_handle.clone()); // TODO: Remove this once https://github.com/foundry-rs/foundry/issues/7955 // This has all processors share an Ethereum node until we can sync controlled nodes - if network == NetworkId::Ethereum { + if network == ExternalNetworkId::Ethereum { eth_handle = eth_handle.or_else(|| Some(handles.0.clone())); } coordinators.push((handles, coord_key)); diff --git a/tests/processor/src/tests/send.rs b/tests/processor/src/tests/send.rs index 62e80c095..e50edc3fe 100644 --- a/tests/processor/src/tests/send.rs +++ b/tests/processor/src/tests/send.rs @@ -8,9 +8,9 @@ use dkg::{Participant, tests::clone_without}; use messages::{sign::SignId, SubstrateContext}; use serai_client::{ - primitives::{BlockHash, NetworkId, Amount, Balance, SeraiAddress}, coins::primitives::{OutInstruction, OutInstructionWithBalance}, - in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch}, + in_instructions::primitives::{Batch, InInstruction, InInstructionWithBalance}, + primitives::{Amount, BlockHash, ExternalBalance, SeraiAddress, EXTERNAL_NETWORKS}, validator_sets::primitives::Session, }; @@ -147,7 +147,7 @@ pub(crate) async fn sign_tx( #[test] fn send_test() { - for network in [NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero] { + for network in EXTERNAL_NETWORKS { let (coordinators, test) = new_test(network); test.run(|ops| async move { @@ -202,10 +202,9 @@ fn send_test() { let amount_minted = Amount( balance_sent.amount.0 - (2 * match network { - NetworkId::Bitcoin => Bitcoin::COST_TO_AGGREGATE, - NetworkId::Ethereum => Ethereum::::COST_TO_AGGREGATE, - NetworkId::Monero => Monero::COST_TO_AGGREGATE, - NetworkId::Serai => panic!("minted for Serai?"), + ExternalNetworkId::Bitcoin => Bitcoin::COST_TO_AGGREGATE, + ExternalNetworkId::Ethereum => Ethereum::::COST_TO_AGGREGATE, + ExternalNetworkId::Monero => Monero::COST_TO_AGGREGATE, }), ); @@ -215,7 +214,7 @@ fn send_test() { block: BlockHash(block_with_tx.unwrap()), instructions: vec![InInstructionWithBalance { instruction, - balance: Balance { coin: balance_sent.coin, amount: amount_minted }, + balance: ExternalBalance { coin: balance_sent.coin, amount: amount_minted }, }], }; @@ -245,7 +244,7 @@ fn send_test() { block: substrate_block_num, burns: vec![OutInstructionWithBalance { instruction: OutInstruction { address: wallet.address(), data: None }, - balance: Balance { coin: balance_sent.coin, amount: amount_minted }, + balance: ExternalBalance { coin: balance_sent.coin, amount: amount_minted }, }], batches: vec![batch.batch.id], },