Move substrate/serai/* to substrate/*

This commit is contained in:
Luke Parker
2023-04-08 03:00:35 -04:00
parent bd06b95c05
commit 7abc8f19cd
41 changed files with 17 additions and 17 deletions

View File

@@ -0,0 +1,29 @@
[package]
name = "serai-primitives"
version = "0.1.0"
description = "Primitives for the Serai blockchain"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/primitives"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
lazy_static = { version = "1", optional = true }
zeroize = { version = "^1.5", features = ["derive"], optional = true }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
serde = { version = "1", features = ["derive"], optional = true }
sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
[features]
std = ["lazy_static", "zeroize", "scale/std", "scale-info/std", "serde", "sp-core/std", "sp-runtime/std"]
default = ["std"]

View File

@@ -0,0 +1,15 @@
AGPL-3.0-only license
Copyright (c) 2022-2023 Luke Parker
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License Version 3 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -0,0 +1,97 @@
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use sp_core::sr25519::{Public, Signature as RistrettoSignature};
#[cfg(feature = "std")]
use sp_core::{Pair as PairTrait, sr25519::Pair};
use sp_runtime::traits::{LookupError, Lookup, StaticLookup};
pub type PublicKey = Public;
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
)]
#[cfg_attr(feature = "std", derive(Zeroize, Serialize, Deserialize))]
pub struct SeraiAddress(pub [u8; 32]);
impl SeraiAddress {
pub fn new(key: [u8; 32]) -> SeraiAddress {
SeraiAddress(key)
}
}
impl From<[u8; 32]> for SeraiAddress {
fn from(key: [u8; 32]) -> SeraiAddress {
SeraiAddress(key)
}
}
impl From<PublicKey> for SeraiAddress {
fn from(key: PublicKey) -> SeraiAddress {
SeraiAddress(key.0)
}
}
impl From<SeraiAddress> for PublicKey {
fn from(address: SeraiAddress) -> PublicKey {
PublicKey::from_raw(address.0)
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for SeraiAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// TODO: Bech32
write!(f, "{:?}", self.0)
}
}
#[cfg(feature = "std")]
pub fn insecure_pair_from_name(name: &str) -> Pair {
Pair::from_string(&format!("//{name}"), None).unwrap()
}
pub struct AccountLookup;
impl Lookup for AccountLookup {
type Source = SeraiAddress;
type Target = PublicKey;
fn lookup(&self, source: SeraiAddress) -> Result<PublicKey, LookupError> {
Ok(PublicKey::from_raw(source.0))
}
}
impl StaticLookup for AccountLookup {
type Source = SeraiAddress;
type Target = PublicKey;
fn lookup(source: SeraiAddress) -> Result<PublicKey, LookupError> {
Ok(source.into())
}
fn unlookup(source: PublicKey) -> SeraiAddress {
source.into()
}
}
pub type Signature = RistrettoSignature;
pub const fn pallet_address(pallet: &'static [u8]) -> SeraiAddress {
let mut address = [0; 32];
let mut set = false;
// Implement a while loop since we can't use a for loop
let mut i = 0;
while i < pallet.len() {
address[i] = pallet[i];
if address[i] != 0 {
set = true;
}
i += 1;
}
// Make sure this address isn't the identity point
// Doesn't do address != [0; 32] since that's not const
assert!(set, "address is the identity point");
SeraiAddress(address)
}

View File

@@ -0,0 +1,47 @@
use core::{
ops::{Add, Sub, Mul},
fmt::Debug,
};
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
/// The type used for amounts within Substrate.
// Distinct from Amount due to Substrate's requirements on this type.
// While Amount could have all the necessary traits implemented, not only are they many, it'd make
// Amount a large type with a variety of misc functions.
// The current type's minimalism sets clear bounds on usage.
pub type SubstrateAmount = u64;
/// The type used for amounts.
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
)]
#[cfg_attr(feature = "std", derive(Zeroize, Serialize, Deserialize))]
pub struct Amount(pub SubstrateAmount);
impl Add for Amount {
type Output = Amount;
fn add(self, other: Amount) -> Amount {
// Explicitly use checked_add so even if range checks are disabled, this is still checked
Amount(self.0.checked_add(other.0).unwrap())
}
}
impl Sub for Amount {
type Output = Amount;
fn sub(self, other: Amount) -> Amount {
Amount(self.0.checked_sub(other.0).unwrap())
}
}
impl Mul for Amount {
type Output = Amount;
fn mul(self, other: Amount) -> Amount {
Amount(self.0.checked_mul(other.0).unwrap())
}
}

View File

@@ -0,0 +1,40 @@
use core::ops::{Add, Sub, Mul};
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use crate::{Coin, 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, Serialize, Deserialize))]
pub struct Balance {
pub coin: Coin,
pub amount: Amount,
}
impl Add<Amount> for Balance {
type Output = Balance;
fn add(self, other: Amount) -> Balance {
Balance { coin: self.coin, amount: self.amount + other }
}
}
impl Sub<Amount> for Balance {
type Output = Balance;
fn sub(self, other: Amount) -> Balance {
Balance { coin: self.coin, amount: self.amount - other }
}
}
impl Mul<Amount> for Balance {
type Output = Balance;
fn mul(self, other: Amount) -> Balance {
Balance { coin: self.coin, amount: self.amount * other }
}
}

View File

@@ -0,0 +1,49 @@
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use sp_core::H256;
/// The type used to identify block numbers.
#[derive(
Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
)]
#[cfg_attr(feature = "std", derive(Zeroize, Serialize, Deserialize))]
pub struct BlockNumber(pub u64);
impl From<u64> for BlockNumber {
fn from(number: u64) -> BlockNumber {
BlockNumber(number)
}
}
/// The type used to identify block hashes.
// This may not be universally compatible
// If a block exists with a hash which isn't 32-bytes, it can be hashed into a value with 32-bytes
// This would require the processor to maintain a mapping of 32-byte IDs to actual hashes, which
// would be fine
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Zeroize, Serialize, Deserialize))]
pub struct BlockHash(pub [u8; 32]);
impl AsRef<[u8]> for BlockHash {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl From<[u8; 32]> for BlockHash {
fn from(hash: [u8; 32]) -> BlockHash {
BlockHash(hash)
}
}
impl From<H256> for BlockHash {
fn from(hash: H256) -> BlockHash {
BlockHash(hash.into())
}
}

View File

@@ -0,0 +1,86 @@
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::{ConstU32, bounded::BoundedVec};
#[cfg(feature = "std")]
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 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 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);
// Max of 8 coins per network
// Since Serai isn't interested in listing tokens, as on-chain DEXs will almost certainly have
// more liquidity, the only reason we'd have so many coins from a network is if there's no DEX
// on-chain
// There's probably no chain with so many *worthwhile* coins and no on-chain DEX
// This could probably be just 4, yet 8 is a hedge for the unforseen
// If necessary, this can be increased with a fork
pub const MAX_COINS_PER_NETWORK: u32 = 8;
/// Network definition.
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Network {
coins: BoundedVec<Coin, ConstU32<{ MAX_COINS_PER_NETWORK }>>,
}
#[cfg(feature = "std")]
impl Zeroize for Network {
fn zeroize(&mut self) {
for coin in self.coins.as_mut() {
coin.zeroize();
}
self.coins.truncate(0);
}
}
impl Network {
#[cfg(feature = "std")]
pub fn new(coins: Vec<Coin>) -> Result<Network, &'static str> {
Ok(Network {
coins: coins.try_into().map_err(|_| "coins length exceeds {MAX_COINS_PER_NETWORK}")?,
})
}
pub fn coins(&self) -> &[Coin] {
&self.coins
}
}
#[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();
}

View File

@@ -0,0 +1,101 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use sp_core::{ConstU32, bounded::BoundedVec};
mod amount;
pub use amount::*;
mod block;
pub use block::*;
mod coins;
pub use coins::*;
mod balance;
pub use balance::*;
mod account;
pub use account::*;
// Monero, our current longest address candidate, has a longest address of featured
// 1 (enum) + 1 (flags) + 64 (two keys) = 66
// When JAMTIS arrives, it'll become 114 bytes
pub const MAX_ADDRESS_LEN: u32 = 128;
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ExternalAddress(BoundedVec<u8, ConstU32<{ MAX_ADDRESS_LEN }>>);
#[cfg(feature = "std")]
impl Zeroize for ExternalAddress {
fn zeroize(&mut self) {
self.0.as_mut().zeroize()
}
}
impl ExternalAddress {
#[cfg(feature = "std")]
pub fn new(address: Vec<u8>) -> Result<ExternalAddress, &'static str> {
Ok(ExternalAddress(address.try_into().map_err(|_| "address length exceeds {MAX_ADDRESS_LEN}")?))
}
pub fn address(&self) -> &[u8] {
self.0.as_ref()
}
#[cfg(feature = "std")]
pub fn consume(self) -> Vec<u8> {
self.0.into_inner()
}
}
impl AsRef<[u8]> for ExternalAddress {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
// Should be enough for a Uniswap v3 call
pub const MAX_DATA_LEN: u32 = 512;
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Data(BoundedVec<u8, ConstU32<{ MAX_DATA_LEN }>>);
#[cfg(feature = "std")]
impl Zeroize for Data {
fn zeroize(&mut self) {
self.0.as_mut().zeroize()
}
}
impl Data {
#[cfg(feature = "std")]
pub fn new(data: Vec<u8>) -> Result<Data, &'static str> {
Ok(Data(data.try_into().map_err(|_| "data length exceeds {MAX_DATA_LEN}")?))
}
pub fn data(&self) -> &[u8] {
self.0.as_ref()
}
#[cfg(feature = "std")]
pub fn consume(self) -> Vec<u8> {
self.0.into_inner()
}
}
impl AsRef<[u8]> for Data {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}