mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-16 17:07:35 +00:00
Use an enum for Coin/NetworkId
It originally wasn't an enum so software which had yet to update before an integration wouldn't error (as now enums are strictly typed). The strict typing is preferable though.
This commit is contained in:
parent
6f3b5f4535
commit
9da0eb69c7
15 changed files with 97 additions and 70 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1310,6 +1310,7 @@ dependencies = [
|
|||
"flexible-transcript",
|
||||
"log",
|
||||
"modular-frost",
|
||||
"parity-scale-codec",
|
||||
"processor-messages",
|
||||
"rand_core 0.6.4",
|
||||
"serai-client",
|
||||
|
|
|
@ -24,6 +24,8 @@ transcript = { package = "flexible-transcript", path = "../crypto/transcript", f
|
|||
ciphersuite = { path = "../crypto/ciphersuite" }
|
||||
frost = { package = "modular-frost", path = "../crypto/frost" }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", features = ["derive"] }
|
||||
|
||||
serai-db = { path = "../common/db" }
|
||||
|
||||
processor-messages = { package = "processor-messages", path = "../processor/messages" }
|
||||
|
|
|
@ -177,18 +177,7 @@ async fn handle_batch_and_burns<D: Db, Pro: Processor>(
|
|||
|
||||
for burn in serai.get_burn_events(hash).await? {
|
||||
if let TokensEvent::Burn { address: _, balance, instruction } = burn {
|
||||
// TODO: Move Network/Coin to an enum and provide this mapping
|
||||
let network = {
|
||||
use serai_client::primitives::*;
|
||||
match balance.coin {
|
||||
BITCOIN => BITCOIN_NET_ID,
|
||||
ETHER => ETHEREUM_NET_ID,
|
||||
DAI => ETHEREUM_NET_ID,
|
||||
MONERO => MONERO_NET_ID,
|
||||
invalid => panic!("burn from unrecognized coin: {invalid:?}"),
|
||||
}
|
||||
};
|
||||
|
||||
let network = balance.coin.network();
|
||||
network_had_event(&mut burns, network);
|
||||
|
||||
// network_had_event should register an entry in burns
|
||||
|
|
|
@ -5,6 +5,8 @@ use transcript::{Transcript, RecommendedTranscript};
|
|||
|
||||
use frost::Participant;
|
||||
|
||||
use scale::Encode;
|
||||
|
||||
use serai_client::validator_sets::primitives::ValidatorSet;
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -18,7 +20,7 @@ pub fn genesis(serai_block: [u8; 32], set: ValidatorSet) -> [u8; 32] {
|
|||
// This locks it to a specific Serai chain
|
||||
genesis.append_message(b"serai_block", serai_block);
|
||||
genesis.append_message(b"session", set.session.0.to_le_bytes());
|
||||
genesis.append_message(b"network", set.network.0.to_le_bytes());
|
||||
genesis.append_message(b"network", set.network.encode());
|
||||
let genesis = genesis.challenge(b"genesis");
|
||||
let genesis_ref: &[u8] = genesis.as_ref();
|
||||
genesis_ref[.. 32].try_into().unwrap()
|
||||
|
|
|
@ -28,9 +28,10 @@ other properties). The network's key is used for all coins on that network.
|
|||
|
||||
| Network | Curve | ID |
|
||||
|----------|-----------|----|
|
||||
| Bitcoin | Secp256k1 | 0 |
|
||||
| Ethereum | Secp256k1 | 1 |
|
||||
| Monero | Ed25519 | 2 |
|
||||
| Serai | Ristretto | 0 |
|
||||
| Bitcoin | Secp256k1 | 1 |
|
||||
| Ethereum | Secp256k1 | 2 |
|
||||
| Monero | Ed25519 | 3 |
|
||||
|
||||
### Coins
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ use bitcoin_serai::bitcoin::{
|
|||
};
|
||||
|
||||
use serai_client::{
|
||||
primitives::{MAX_DATA_LEN, BITCOIN, BITCOIN_NET_ID, NetworkId, Amount, Balance},
|
||||
primitives::{MAX_DATA_LEN, Coin as SeraiCoin, NetworkId, Amount, Balance},
|
||||
coins::bitcoin::Address,
|
||||
};
|
||||
|
||||
|
@ -97,7 +97,7 @@ impl OutputTrait for Output {
|
|||
}
|
||||
|
||||
fn balance(&self) -> Balance {
|
||||
Balance { coin: BITCOIN, amount: Amount(self.output.value()) }
|
||||
Balance { coin: SeraiCoin::Bitcoin, amount: Amount(self.output.value()) }
|
||||
}
|
||||
|
||||
fn data(&self) -> &[u8] {
|
||||
|
@ -293,7 +293,7 @@ impl Coin for Bitcoin {
|
|||
|
||||
type Address = Address;
|
||||
|
||||
const NETWORK: NetworkId = BITCOIN_NET_ID;
|
||||
const NETWORK: NetworkId = NetworkId::Bitcoin;
|
||||
const ID: &'static str = "Bitcoin";
|
||||
const CONFIRMATIONS: usize = 6;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ use monero_serai::{
|
|||
use tokio::time::sleep;
|
||||
|
||||
pub use serai_client::{
|
||||
primitives::{MAX_DATA_LEN, MONERO, MONERO_NET_ID, NetworkId, Amount, Balance},
|
||||
primitives::{MAX_DATA_LEN, Coin as SeraiCoin, NetworkId, Amount, Balance},
|
||||
coins::monero::Address,
|
||||
};
|
||||
|
||||
|
@ -66,7 +66,7 @@ impl OutputTrait for Output {
|
|||
}
|
||||
|
||||
fn balance(&self) -> Balance {
|
||||
Balance { coin: MONERO, amount: Amount(self.0.commitment().amount) }
|
||||
Balance { coin: SeraiCoin::Monero, amount: Amount(self.0.commitment().amount) }
|
||||
}
|
||||
|
||||
fn data(&self) -> &[u8] {
|
||||
|
@ -221,7 +221,7 @@ impl Coin for Monero {
|
|||
|
||||
type Address = Address;
|
||||
|
||||
const NETWORK: NetworkId = MONERO_NET_ID;
|
||||
const NETWORK: NetworkId = NetworkId::Monero;
|
||||
const ID: &'static str = "Monero";
|
||||
const CONFIRMATIONS: usize = 10;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use serai_db::{DbTxn, Db, MemDb};
|
|||
|
||||
use sp_application_crypto::sr25519;
|
||||
use serai_client::{
|
||||
primitives::{MONERO_NET_ID, BlockHash},
|
||||
primitives::{BlockHash, NetworkId},
|
||||
validator_sets::primitives::{Session, ValidatorSet},
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,7 @@ use crate::{
|
|||
};
|
||||
|
||||
const ID: KeyGenId =
|
||||
KeyGenId { set: ValidatorSet { session: Session(1), network: MONERO_NET_ID }, attempt: 3 };
|
||||
KeyGenId { set: ValidatorSet { session: Session(1), network: NetworkId::Monero }, attempt: 3 };
|
||||
|
||||
pub async fn test_key_gen<C: Coin>() {
|
||||
let mut entropies = HashMap::new();
|
||||
|
|
|
@ -30,20 +30,20 @@ async fn test_substrate_signer() {
|
|||
SignId { key: keys[&participant_one].group_key().to_bytes().to_vec(), id: block.0, attempt: 0 };
|
||||
|
||||
let batch = Batch {
|
||||
network: MONERO_NET_ID,
|
||||
network: NetworkId::Monero,
|
||||
id: 5,
|
||||
block,
|
||||
instructions: vec![
|
||||
InInstructionWithBalance {
|
||||
instruction: InInstruction::Transfer(SeraiAddress([0xbb; 32])),
|
||||
balance: Balance { coin: BITCOIN, amount: Amount(1000) },
|
||||
balance: Balance { coin: Coin::Bitcoin, amount: Amount(1000) },
|
||||
},
|
||||
InInstructionWithBalance {
|
||||
instruction: InInstruction::Call(ApplicationCall {
|
||||
application: Application::DEX,
|
||||
data: Data::new(vec![0xcc; 128]).unwrap(),
|
||||
}),
|
||||
balance: Balance { coin: MONERO, amount: Amount(9999999999999999) },
|
||||
balance: Balance { coin: Coin::Monero, amount: Amount(9999999999999999) },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rand_core::{RngCore, OsRng};
|
||||
|
||||
use serai_client::{
|
||||
primitives::{BITCOIN_NET_ID, BITCOIN, BlockHash, SeraiAddress, Amount, Balance},
|
||||
primitives::{Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress},
|
||||
in_instructions::{
|
||||
primitives::{InInstruction, InInstructionWithBalance, Batch},
|
||||
InInstructionsEvent,
|
||||
|
@ -15,7 +15,7 @@ use common::{serai, in_instructions::provide_batch};
|
|||
|
||||
serai_test!(
|
||||
async fn publish_batch() {
|
||||
let network = BITCOIN_NET_ID;
|
||||
let network = NetworkId::Bitcoin;
|
||||
let id = 0;
|
||||
|
||||
let mut block_hash = BlockHash([0; 32]);
|
||||
|
@ -24,7 +24,7 @@ serai_test!(
|
|||
let mut address = SeraiAddress::new([0; 32]);
|
||||
OsRng.fill_bytes(&mut address.0);
|
||||
|
||||
let coin = BITCOIN;
|
||||
let coin = Coin::Bitcoin;
|
||||
let amount = Amount(OsRng.next_u64().saturating_add(1));
|
||||
let balance = Balance { coin, amount };
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use sp_core::Pair;
|
|||
use serai_client::{
|
||||
subxt::config::extrinsic_params::BaseExtrinsicParamsBuilder,
|
||||
primitives::{
|
||||
BITCOIN_NET_ID, BITCOIN, BlockHash, SeraiAddress, Amount, Balance, Data, ExternalAddress,
|
||||
Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, Data, ExternalAddress,
|
||||
insecure_pair_from_name,
|
||||
},
|
||||
in_instructions::{
|
||||
|
@ -21,7 +21,7 @@ use common::{serai, tx::publish_tx, in_instructions::provide_batch};
|
|||
|
||||
serai_test!(
|
||||
async fn burn() {
|
||||
let network = BITCOIN_NET_ID;
|
||||
let network = NetworkId::Bitcoin;
|
||||
let id = 0;
|
||||
|
||||
let mut block_hash = BlockHash([0; 32]);
|
||||
|
@ -31,7 +31,7 @@ serai_test!(
|
|||
let public = pair.public();
|
||||
let address = SeraiAddress::from(public);
|
||||
|
||||
let coin = BITCOIN;
|
||||
let coin = Coin::Bitcoin;
|
||||
let amount = Amount(OsRng.next_u64().saturating_add(1));
|
||||
let balance = Balance { coin, amount };
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ use rand_core::{RngCore, OsRng};
|
|||
use sp_core::{sr25519::Public, Pair};
|
||||
|
||||
use serai_client::{
|
||||
primitives::{
|
||||
BITCOIN_NET_ID, ETHEREUM_NET_ID, MONERO_NET_ID, BITCOIN_NET, insecure_pair_from_name,
|
||||
},
|
||||
primitives::{NETWORKS, NetworkId, insecure_pair_from_name},
|
||||
validator_sets::{
|
||||
primitives::{Session, ValidatorSet},
|
||||
ValidatorSetsEvent,
|
||||
|
@ -18,7 +16,7 @@ use common::{serai, validator_sets::vote_in_keys};
|
|||
|
||||
serai_test!(
|
||||
async fn vote_keys() {
|
||||
let network = BITCOIN_NET_ID;
|
||||
let network = NetworkId::Bitcoin;
|
||||
let set = ValidatorSet { session: Session(0), network };
|
||||
|
||||
let public = insecure_pair_from_name("Alice").public();
|
||||
|
@ -40,7 +38,7 @@ serai_test!(
|
|||
.get_new_set_events(serai.get_block_by_number(0).await.unwrap().unwrap().hash())
|
||||
.await
|
||||
.unwrap(),
|
||||
[BITCOIN_NET_ID, ETHEREUM_NET_ID, MONERO_NET_ID]
|
||||
[NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero]
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|network| ValidatorSetsEvent::NewSet {
|
||||
|
@ -50,7 +48,7 @@ serai_test!(
|
|||
);
|
||||
|
||||
let set_data = serai.get_validator_set(set).await.unwrap().unwrap();
|
||||
assert_eq!(set_data.network, *BITCOIN_NET);
|
||||
assert_eq!(set_data.network, NETWORKS[&NetworkId::Bitcoin]);
|
||||
let participants_ref: &[_] = set_data.participants.as_ref();
|
||||
assert_eq!(participants_ref, [(public, set_data.bond)].as_ref());
|
||||
|
||||
|
|
|
@ -37,16 +37,16 @@ fn testnet_genesis(
|
|||
transaction_payment: Default::default(),
|
||||
|
||||
assets: AssetsConfig {
|
||||
assets: [BITCOIN, ETHER, DAI, MONERO]
|
||||
assets: [Coin::Bitcoin, Coin::Ether, Coin::Dai, Coin::Monero]
|
||||
.iter()
|
||||
.map(|coin| (*coin, TOKENS_ADDRESS.into(), true, 1))
|
||||
.collect(),
|
||||
metadata: vec![
|
||||
(BITCOIN, b"Bitcoin".to_vec(), b"BTC".to_vec(), 8),
|
||||
(Coin::Bitcoin, b"Bitcoin".to_vec(), b"BTC".to_vec(), 8),
|
||||
// Reduce to 8 decimals to feasibly fit within u64 (instead of its native u256)
|
||||
(ETHER, b"Ether".to_vec(), b"ETH".to_vec(), 8),
|
||||
(DAI, b"Dai Stablecoin".to_vec(), b"DAI".to_vec(), 8),
|
||||
(MONERO, b"Monero".to_vec(), b"XMR".to_vec(), 12),
|
||||
(Coin::Ether, b"Ether".to_vec(), b"ETH".to_vec(), 8),
|
||||
(Coin::Dai, b"Dai Stablecoin".to_vec(), b"DAI".to_vec(), 8),
|
||||
(Coin::Monero, b"Monero".to_vec(), b"XMR".to_vec(), 12),
|
||||
],
|
||||
accounts: vec![],
|
||||
},
|
||||
|
@ -54,9 +54,9 @@ fn testnet_genesis(
|
|||
validator_sets: ValidatorSetsConfig {
|
||||
bond: Amount(1_000_000 * 10_u64.pow(8)),
|
||||
networks: vec![
|
||||
(BITCOIN_NET_ID, BITCOIN_NET.clone()),
|
||||
(ETHEREUM_NET_ID, ETHEREUM_NET.clone()),
|
||||
(MONERO_NET_ID, MONERO_NET.clone()),
|
||||
(NetworkId::Bitcoin, NETWORKS[&NetworkId::Bitcoin].clone()),
|
||||
(NetworkId::Ethereum, NETWORKS[&NetworkId::Ethereum].clone()),
|
||||
(NetworkId::Monero, NETWORKS[&NetworkId::Monero].clone()),
|
||||
],
|
||||
participants: validators.iter().map(|name| account_from_name(name)).collect(),
|
||||
},
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#[cfg(feature = "std")]
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
|
@ -12,32 +15,35 @@ use serde::{Serialize, Deserialize};
|
|||
/// The type used to identify networks.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize, Serialize, Deserialize))]
|
||||
pub struct NetworkId(pub u16);
|
||||
impl From<u16> for NetworkId {
|
||||
fn from(network: u16) -> NetworkId {
|
||||
NetworkId(network)
|
||||
}
|
||||
pub enum NetworkId {
|
||||
Serai,
|
||||
Bitcoin,
|
||||
Ethereum,
|
||||
Monero,
|
||||
}
|
||||
|
||||
pub const BITCOIN_NET_ID: NetworkId = NetworkId(0);
|
||||
pub const ETHEREUM_NET_ID: NetworkId = NetworkId(1);
|
||||
pub const MONERO_NET_ID: NetworkId = NetworkId(2);
|
||||
|
||||
/// The type used to identify coins.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize, Serialize, Deserialize))]
|
||||
pub struct Coin(pub u32);
|
||||
impl From<u32> for Coin {
|
||||
fn from(coin: u32) -> Coin {
|
||||
Coin(coin)
|
||||
}
|
||||
pub enum Coin {
|
||||
Serai,
|
||||
Bitcoin,
|
||||
Ether,
|
||||
Dai,
|
||||
Monero,
|
||||
}
|
||||
|
||||
pub const SERAI: Coin = Coin(0);
|
||||
pub const BITCOIN: Coin = Coin(1);
|
||||
pub const ETHER: Coin = Coin(2);
|
||||
pub const DAI: Coin = Coin(3);
|
||||
pub const MONERO: Coin = Coin(4);
|
||||
impl Coin {
|
||||
pub fn network(&self) -> NetworkId {
|
||||
match self {
|
||||
Coin::Serai => NetworkId::Serai,
|
||||
Coin::Bitcoin => NetworkId::Bitcoin,
|
||||
Coin::Ether => NetworkId::Ethereum,
|
||||
Coin::Dai => NetworkId::Ethereum,
|
||||
Coin::Monero => NetworkId::Monero,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Max of 8 coins per network
|
||||
// Since Serai isn't interested in listing tokens, as on-chain DEXs will almost certainly have
|
||||
|
@ -68,6 +74,17 @@ impl Zeroize for Network {
|
|||
impl Network {
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new(coins: Vec<Coin>) -> Result<Network, &'static str> {
|
||||
if coins.is_empty() {
|
||||
Err("no coins provided")?;
|
||||
}
|
||||
|
||||
let network = coins[0].network();
|
||||
for coin in coins.iter().skip(1) {
|
||||
if coin.network() != network {
|
||||
Err("coins have different networks")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Network {
|
||||
coins: coins.try_into().map_err(|_| "coins length exceeds {MAX_COINS_PER_NETWORK}")?,
|
||||
})
|
||||
|
@ -80,7 +97,9 @@ impl Network {
|
|||
|
||||
#[cfg(feature = "std")]
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref BITCOIN_NET: Network = Network::new(vec![BITCOIN]).unwrap();
|
||||
pub static ref ETHEREUM_NET: Network = Network::new(vec![ETHER, DAI]).unwrap();
|
||||
pub static ref MONERO_NET: Network = Network::new(vec![MONERO]).unwrap();
|
||||
pub static ref NETWORKS: HashMap<NetworkId, Network> = HashMap::from([
|
||||
(NetworkId::Bitcoin, Network::new(vec![Coin::Bitcoin]).unwrap()),
|
||||
(NetworkId::Ethereum, Network::new(vec![Coin::Ether, Coin::Dai]).unwrap()),
|
||||
(NetworkId::Monero, Network::new(vec![Coin::Monero]).unwrap()),
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -247,6 +247,21 @@ impl transaction_payment::Config for Runtime {
|
|||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub struct SeraiAssetBenchmarkHelper;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
impl assets::BenchmarkHelper<Coin> for SeraiAssetBenchmarkHelper {
|
||||
fn create_asset_id_parameter(id: u32) -> Coin {
|
||||
match (id % 4) + 1 {
|
||||
1 => Coin::Bitcoin,
|
||||
2 => Coin::Ether,
|
||||
3 => Coin::Dai,
|
||||
4 => Coin::Monero,
|
||||
_ => panic!("(id % 4) + 1 wasn't in [1, 4]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl assets::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Balance = SubstrateAmount;
|
||||
|
@ -275,7 +290,7 @@ impl assets::Config for Runtime {
|
|||
|
||||
type WeightInfo = assets::weights::SubstrateWeight<Runtime>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
type BenchmarkHelper = SeraiAssetBenchmarkHelper;
|
||||
}
|
||||
|
||||
impl tokens::Config for Runtime {
|
||||
|
|
Loading…
Reference in a new issue