mirror of
https://github.com/serai-dex/serai.git
synced 2025-04-22 22:18:15 +00:00
Add Substrate "assets" pallet
While over-engineered for our purposes, it's still usable. Also cleans the runtime a bit.
This commit is contained in:
parent
daa88a051f
commit
f760c09006
7 changed files with 139 additions and 57 deletions
Cargo.lock
substrate
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -4889,6 +4889,21 @@ dependencies = [
|
|||
"libm 0.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-assets"
|
||||
version = "4.0.0-dev"
|
||||
source = "git+https://github.com/serai-dex/substrate#6dc38b0ba11dff62c1042ab0fa21d0b55a64bf6e"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-balances"
|
||||
version = "4.0.0-dev"
|
||||
|
@ -7309,6 +7324,7 @@ dependencies = [
|
|||
"frame-system",
|
||||
"frame-system-rpc-runtime-api",
|
||||
"hex-literal",
|
||||
"pallet-assets",
|
||||
"pallet-balances",
|
||||
"pallet-session",
|
||||
"pallet-tendermint",
|
||||
|
@ -7316,6 +7332,7 @@ dependencies = [
|
|||
"pallet-transaction-payment-rpc-runtime-api",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"serai-primitives",
|
||||
"sp-api",
|
||||
"sp-application-crypto",
|
||||
"sp-block-builder",
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use sp_core::{Pair as PairTrait, sr25519::Pair};
|
||||
use sp_core::{Decode, Pair as PairTrait, sr25519::Pair};
|
||||
use sp_runtime::traits::TrailingZeroInput;
|
||||
|
||||
use sc_service::ChainType;
|
||||
|
||||
use serai_primitives::{Amount, COIN, Coin};
|
||||
use serai_primitives::*;
|
||||
use pallet_tendermint::crypto::Public;
|
||||
|
||||
use serai_runtime::{
|
||||
WASM_BINARY, AccountId, opaque::SessionKeys, GenesisConfig, SystemConfig, BalancesConfig,
|
||||
ValidatorSetsConfig, SessionConfig,
|
||||
AssetsConfig, ValidatorSetsConfig, SessionConfig,
|
||||
};
|
||||
|
||||
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
|
||||
|
@ -29,11 +31,25 @@ fn testnet_genesis(
|
|||
(key, key, SessionKeys { tendermint: Public::from(key) })
|
||||
};
|
||||
|
||||
// TODO: Replace with a call to the pallet to ask for its account
|
||||
let owner = AccountId::decode(&mut TrailingZeroInput::new(b"tokens")).unwrap();
|
||||
|
||||
GenesisConfig {
|
||||
system: SystemConfig { code: wasm_binary.to_vec() },
|
||||
balances: BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||
},
|
||||
assets: AssetsConfig {
|
||||
assets: [BITCOIN, ETHER, DAI, MONERO].iter().map(|coin| (*coin, owner, true, 1)).collect(),
|
||||
metadata: vec![
|
||||
(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),
|
||||
],
|
||||
accounts: vec![],
|
||||
},
|
||||
transaction_payment: Default::default(),
|
||||
|
||||
validator_sets: ValidatorSetsConfig {
|
||||
|
|
|
@ -25,7 +25,7 @@ sp-inherents = { git = "https://github.com/serai-dex/substrate", default-feature
|
|||
sp-offchain = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-session = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-transaction-pool = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-block-builder = { git = "https://github.com/serai-dex/substrate", default-features = false}
|
||||
sp-block-builder = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
||||
|
@ -36,7 +36,10 @@ frame-support = { git = "https://github.com/serai-dex/substrate", default-featur
|
|||
frame-executive = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/substrate", default-features = false, optional = true }
|
||||
|
||||
serai-primitives = { path = "../serai/primitives", default-features = false }
|
||||
|
||||
pallet-balances = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
pallet-assets = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
||||
validator-sets-pallet = { path = "../validator-sets/pallet", default-features = false }
|
||||
|
@ -72,7 +75,10 @@ std = [
|
|||
"frame-support/std",
|
||||
"frame-executive/std",
|
||||
|
||||
"serai-primitives/std",
|
||||
|
||||
"pallet-balances/std",
|
||||
"pallet-assets/std",
|
||||
"pallet-transaction-payment/std",
|
||||
|
||||
"validator-sets-pallet/std",
|
||||
|
@ -93,6 +99,7 @@ runtime-benchmarks = [
|
|||
"frame-benchmarking/runtime-benchmarks",
|
||||
|
||||
"pallet-balances/runtime-benchmarks",
|
||||
"pallet-assets/runtime-benchmarks",
|
||||
|
||||
"pallet-tendermint/runtime-benchmarks",
|
||||
]
|
||||
|
|
|
@ -28,7 +28,10 @@ use frame_support::{
|
|||
};
|
||||
pub use frame_system::Call as SystemCall;
|
||||
|
||||
use serai_primitives::Coin;
|
||||
|
||||
pub use pallet_balances::Call as BalancesCall;
|
||||
pub use pallet_assets::Call as AssetsCall;
|
||||
use pallet_transaction_payment::CurrencyAdapter;
|
||||
|
||||
use pallet_session::PeriodicSessions;
|
||||
|
@ -40,6 +43,11 @@ pub type BlockNumber = u32;
|
|||
pub type AccountId = Public;
|
||||
|
||||
/// Balance of an account.
|
||||
// Distinct from serai-primitives Amount due to Substrate's requirements on this type.
|
||||
// If Amount could be dropped in here, it would be.
|
||||
// While Amount could have all the necessary traits implemented, not only are they many, yet it'd
|
||||
// make Amount a larger type, providing more operations than desired.
|
||||
// The current type's minimalism sets clear bounds on usage.
|
||||
pub type Balance = u64;
|
||||
|
||||
/// Index of a transaction in the chain, for a given account.
|
||||
|
@ -69,8 +77,7 @@ use opaque::SessionKeys;
|
|||
#[sp_version::runtime_version]
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("serai"),
|
||||
// TODO: "core"?
|
||||
impl_name: create_runtime_str!("turoctocrab"),
|
||||
impl_name: create_runtime_str!("core"),
|
||||
authoring_version: 1,
|
||||
// TODO: 1? Do we prefer some level of compatibility or our own path?
|
||||
spec_version: 100,
|
||||
|
@ -97,14 +104,6 @@ pub fn native_version() -> NativeVersion {
|
|||
|
||||
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
|
||||
|
||||
// Unit = the base number of indivisible units for balances
|
||||
const UNIT: Balance = 1_000_000_000_000;
|
||||
const MILLIUNIT: Balance = 1_000_000_000;
|
||||
|
||||
const fn deposit(items: u32, bytes: u32) -> Balance {
|
||||
(items as Balance * UNIT + (bytes as Balance) * (5 * MILLIUNIT / 100)) / 10
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: BlockNumber = 2400;
|
||||
pub const Version: RuntimeVersion = VERSION;
|
||||
|
@ -119,16 +118,6 @@ parameter_types! {
|
|||
Weight::from_ref_time(2u64 * WEIGHT_REF_TIME_PER_SECOND).set_proof_size(u64::MAX),
|
||||
NORMAL_DISPATCH_RATIO,
|
||||
);
|
||||
|
||||
pub const DepositPerItem: Balance = deposit(1, 0);
|
||||
pub const DepositPerByte: Balance = deposit(0, 1);
|
||||
pub const DeletionQueueDepth: u32 = 128;
|
||||
// The lazy deletion runs inside on_initialize.
|
||||
pub DeletionWeightLimit: Weight = BlockWeights::get()
|
||||
.per_class
|
||||
.get(DispatchClass::Normal)
|
||||
.max_total
|
||||
.unwrap_or(BlockWeights::get().max_block);
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
|
@ -173,6 +162,37 @@ impl pallet_balances::Config for Runtime {
|
|||
type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
|
||||
}
|
||||
|
||||
impl pallet_assets::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Balance = Balance;
|
||||
type Currency = Balances;
|
||||
|
||||
type AssetId = Coin;
|
||||
type AssetIdParameter = Coin;
|
||||
type StringLimit = ConstU32<32>;
|
||||
|
||||
// Don't allow anyone to create assets
|
||||
type CreateOrigin =
|
||||
frame_support::traits::AsEnsureOriginWithArg<frame_system::EnsureNever<AccountId>>;
|
||||
type ForceOrigin = frame_system::EnsureRoot<AccountId>;
|
||||
|
||||
// Don't charge fees nor kill accounts
|
||||
type RemoveItemsLimit = ConstU32<0>;
|
||||
type AssetDeposit = ConstU64<0>;
|
||||
type AssetAccountDeposit = ConstU64<0>;
|
||||
type MetadataDepositBase = ConstU64<0>;
|
||||
type MetadataDepositPerByte = ConstU64<0>;
|
||||
type ApprovalDeposit = ConstU64<0>;
|
||||
|
||||
// Unused hooks
|
||||
type Freezer = ();
|
||||
type Extra = ();
|
||||
|
||||
type WeightInfo = pallet_assets::weights::SubstrateWeight<Runtime>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
impl pallet_transaction_payment::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type OnChargeTransaction = CurrencyAdapter<Balances, ()>;
|
||||
|
@ -242,6 +262,7 @@ construct_runtime!(
|
|||
{
|
||||
System: frame_system,
|
||||
Balances: pallet_balances,
|
||||
Assets: pallet_assets,
|
||||
TransactionPayment: pallet_transaction_payment,
|
||||
|
||||
ValidatorSets: validator_sets_pallet,
|
||||
|
|
31
substrate/serai/primitives/src/amount.rs
Normal file
31
substrate/serai/primitives/src/amount.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use core::{ops::{Add, Mul}};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// The type used for amounts.
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
||||
pub struct Amount(pub u64);
|
||||
|
||||
/// One whole coin with eight decimals.
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
pub const COIN: Amount = Amount(1_000_000_00);
|
||||
|
||||
impl Add for Amount {
|
||||
type Output = Amount;
|
||||
fn add(self, other: Amount) -> Amount {
|
||||
Amount(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Amount {
|
||||
type Output = Amount;
|
||||
fn mul(self, other: Amount) -> Amount {
|
||||
Amount(self.0 * other.0)
|
||||
}
|
||||
}
|
19
substrate/serai/primitives/src/coins.rs
Normal file
19
substrate/serai/primitives/src/coins.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// The type used to identify coins.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
||||
pub struct Coin(pub u32);
|
||||
impl From<u32> for Coin {
|
||||
fn from(coin: u32) -> Coin {
|
||||
Coin(coin)
|
||||
}
|
||||
}
|
||||
|
||||
pub const BITCOIN: Coin = Coin(0);
|
||||
pub const ETHER: Coin = Coin(1);
|
||||
pub const DAI: Coin = Coin(2);
|
||||
pub const MONERO: Coin = Coin(3);
|
|
@ -1,36 +1,7 @@
|
|||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use core::ops::{Add, Mul};
|
||||
mod amount;
|
||||
pub use amount::*;
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// The type used for amounts.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
||||
pub struct Amount(pub u64);
|
||||
|
||||
impl Add<Amount> for Amount {
|
||||
type Output = Amount;
|
||||
fn add(self, other: Amount) -> Amount {
|
||||
Amount(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Amount> for Amount {
|
||||
type Output = Amount;
|
||||
fn mul(self, other: Amount) -> Amount {
|
||||
Amount(self.0 * other.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// One whole coin with eight decimals.
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
pub const COIN: Amount = Amount(1_000_000_00);
|
||||
|
||||
/// The type used to identify coins.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
||||
pub struct Coin(pub u32);
|
||||
mod coins;
|
||||
pub use coins::*;
|
||||
|
|
Loading…
Reference in a new issue