Have the coins pallet emit events via serai_core_pallet

`serai_core_pallet` solely defines an accumulator for the events. We use the
traditional `frame_system::Events` to store them for now and enable retrieval.
This commit is contained in:
Luke Parker
2025-09-19 22:12:45 -04:00
parent 3f5150b3fa
commit 3cb9432daa
12 changed files with 188 additions and 129 deletions

17
Cargo.lock generated
View File

@@ -1836,9 +1836,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.47" version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -1846,9 +1846,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.47" version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -8899,14 +8899,14 @@ dependencies = [
name = "serai-coins-pallet" name = "serai-coins-pallet"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"borsh",
"frame-support", "frame-support",
"frame-system", "frame-system",
"parity-scale-codec", "parity-scale-codec",
"serai-primitives", "serai-abi",
"serai-core-pallet",
"sp-core", "sp-core",
"sp-io", "sp-io",
"sp-runtime",
"sp-std",
] ]
[[package]] [[package]]
@@ -9029,7 +9029,6 @@ dependencies = [
"parity-scale-codec", "parity-scale-codec",
"serai-abi", "serai-abi",
"sp-core", "sp-core",
"sp-io",
] ]
[[package]] [[package]]
@@ -9697,7 +9696,6 @@ dependencies = [
name = "serai-runtime" name = "serai-runtime"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"borsh",
"frame-executive", "frame-executive",
"frame-support", "frame-support",
"frame-system", "frame-system",
@@ -9724,7 +9722,6 @@ dependencies = [
"serai-abi", "serai-abi",
"serai-validator-sets-pallet", "serai-validator-sets-pallet",
"sp-core", "sp-core",
"sp-io",
] ]
[[package]] [[package]]

View File

@@ -44,6 +44,15 @@ pub enum Event {
/// The coins minted. /// The coins minted.
coins: Balance, coins: Balance,
}, },
/// The specified coins were transferred.
Transfer {
/// The address transferred from.
from: SeraiAddress,
/// The address transferred to.
to: SeraiAddress,
/// The coins transferred.
coins: Balance,
},
/// The specified coins were burnt. /// The specified coins were burnt.
Burn { Burn {
/// The address burnt from. /// The address burnt from.
@@ -58,13 +67,4 @@ pub enum Event {
/// The `OutInstruction` specified, and the coins burnt. /// The `OutInstruction` specified, and the coins burnt.
instruction: OutInstructionWithBalance, instruction: OutInstructionWithBalance,
}, },
/// The specified coins were transferred.
Transfer {
/// The address transferred from.
from: SeraiAddress,
/// The address transferred to.
to: SeraiAddress,
/// The coins transferred.
coins: Balance,
},
} }

View File

@@ -96,3 +96,44 @@ pub enum Event {
/// The event for `InInstruction`s. /// The event for `InInstruction`s.
InInstructions(in_instructions::Event) = 7, InInstructions(in_instructions::Event) = 7,
} }
impl From<system::Event> for Event {
fn from(event: system::Event) -> Self {
Self::System(event)
}
}
impl From<coins::Event> for Event {
fn from(event: coins::Event) -> Self {
Self::Coins(event)
}
}
impl From<validator_sets::Event> for Event {
fn from(event: validator_sets::Event) -> Self {
Self::ValidatorSets(event)
}
}
impl From<signals::Event> for Event {
fn from(event: signals::Event) -> Self {
Self::Signals(event)
}
}
impl From<dex::Event> for Event {
fn from(event: dex::Event) -> Self {
Self::Dex(event)
}
}
impl From<genesis_liquidity::Event> for Event {
fn from(event: genesis_liquidity::Event) -> Self {
Self::GenesisLiquidity(event)
}
}
impl From<economic_security::Event> for Event {
fn from(event: economic_security::Event) -> Self {
Self::EconomicSecurity(event)
}
}
impl From<in_instructions::Event> for Event {
fn from(event: in_instructions::Event) -> Self {
Self::InInstructions(event)
}
}

View File

@@ -19,37 +19,44 @@ workspace = true
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
serai-primitives = { path = "../primitives", default-features = false, features = ["serde", "non_canonical_scale_derivations"] } serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
serai-core-pallet = { path = "../core", default-features = false }
[dev-dependencies] [dev-dependencies]
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, features = ["std"] } sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, features = ["std"] }
[features] [features]
std = [ std = [
"scale/std",
"sp-core/std", "sp-core/std",
"sp-std/std",
"sp-runtime/std",
"frame-system/std", "frame-system/std",
"frame-support/std", "frame-support/std",
"serai-primitives/std", "serai-abi/std",
"serai-core-pallet/std",
] ]
try-runtime = [ try-runtime = [
"frame-system/try-runtime", "frame-system/try-runtime",
"frame-support/try-runtime", "frame-support/try-runtime",
"serai-abi/try-runtime",
"serai-core-pallet/try-runtime",
] ]
runtime-benchmarks = [ runtime-benchmarks = [
"frame-system/runtime-benchmarks", "frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
"serai-core-pallet/runtime-benchmarks",
] ]
default = ["std"] default = ["std"]

View File

@@ -11,7 +11,8 @@ mod mock;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use serai_primitives::balance::ExternalBalance; use serai_abi::primitives::balance::ExternalBalance;
use serai_core_pallet::Pallet as Core;
/// The decider for if a mint is allowed or not. /// The decider for if a mint is allowed or not.
pub trait AllowMint { pub trait AllowMint {
@@ -27,7 +28,7 @@ impl AllowMint for AlwaysAllowMint {
} }
} }
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
#[frame_support::pallet] #[frame_support::pallet]
mod pallet { mod pallet {
use core::any::TypeId; use core::any::TypeId;
@@ -38,7 +39,10 @@ mod pallet {
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
use frame_support::pallet_prelude::*; use frame_support::pallet_prelude::*;
use serai_primitives::{coin::*, balance::*, instructions::OutInstructionWithBalance}; use serai_abi::{
primitives::{coin::*, balance::*, instructions::OutInstructionWithBalance},
coins::Event,
};
use super::*; use super::*;
@@ -53,7 +57,9 @@ mod pallet {
/// The configuration of this pallet. /// The configuration of this pallet.
#[pallet::config] #[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config<AccountId = Public> { pub trait Config<I: 'static = ()>:
frame_system::Config<AccountId = Public> + serai_core_pallet::Config
{
/// What decides if mints are allowed. /// What decides if mints are allowed.
type AllowMint: AllowMint; type AllowMint: AllowMint;
} }
@@ -90,42 +96,6 @@ mod pallet {
BurnWithInstructionNotAllowed, BurnWithInstructionNotAllowed,
} }
/// An event emitted.
#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
/// Coins were minted.
Mint {
/// The account minted to.
to: Public,
/// The balance minted.
balance: Balance,
},
/// Coins were transferred.
Transfer {
/// The account transferred from.
from: Public,
/// The account transferred to.
to: Public,
/// The balance transferred.
balance: Balance,
},
/// Coins were burnt.
Burn {
/// The account burnt from.
from: Public,
/// The balance burnt.
balance: Balance,
},
/// Coins were burnt with an instruction.
BurnWithInstruction {
/// The account burnt from.
from: Public,
/// The instruction, and associated balance.
instruction: OutInstructionWithBalance,
},
}
/// The Pallet struct. /// The Pallet struct.
#[pallet::pallet] #[pallet::pallet]
pub struct Pallet<T, I = ()>(_); pub struct Pallet<T, I = ()>(_);
@@ -151,6 +121,16 @@ mod pallet {
} }
impl<T: Config<I>, I: 'static> Pallet<T, I> { impl<T: Config<I>, I: 'static> Pallet<T, I> {
fn emit_event(event: Event) {
if TypeId::of::<I>() == TypeId::of::<CoinsInstance>() {
Core::<T>::emit_event(event)
} else if TypeId::of::<I>() == TypeId::of::<LiquidityTokensInstance>() {
// The DEX pallet is expected to emit this event
} else {
panic!("unrecognized instance type for `coins::Pallet` made it into an execution context")
}
}
/// Returns the balance of `coin` for the specified account. /// Returns the balance of `coin` for the specified account.
pub fn balance( pub fn balance(
of: impl scale::EncodeLike<Public>, of: impl scale::EncodeLike<Public>,
@@ -195,10 +175,10 @@ mod pallet {
/// Mint `balance` to the given account. /// Mint `balance` to the given account.
/// ///
/// Errors if any amount overflows. /// Errors if any amount overflows.
pub fn mint(to: Public, balance: Balance) -> Result<(), Error<T, I>> { pub fn mint(to: Public, coins: Balance) -> Result<(), Error<T, I>> {
{ {
// If this is an external coin, check if we can mint it // If this is an external coin, check if we can mint it
let external_balance = ExternalBalance::try_from(balance); let external_balance = ExternalBalance::try_from(coins);
let can_mint_external = external_balance.as_ref().map(T::AllowMint::is_allowed); let can_mint_external = external_balance.as_ref().map(T::AllowMint::is_allowed);
// If it was native to the Serai network, we can always mint it // If it was native to the Serai network, we can always mint it
let can_mint = can_mint_external.unwrap_or(true); let can_mint = can_mint_external.unwrap_or(true);
@@ -208,14 +188,14 @@ mod pallet {
} }
// update the balance // update the balance
Self::increase_balance_internal(to, balance)?; Self::increase_balance_internal(to, coins)?;
// update the supply // update the supply
let new_supply = (Supply::<T, I>::get(balance.coin) + balance.amount) let new_supply =
.ok_or(Error::<T, I>::AmountOverflowed)?; (Supply::<T, I>::get(coins.coin) + coins.amount).ok_or(Error::<T, I>::AmountOverflowed)?;
Supply::<T, I>::set(balance.coin, new_supply); Supply::<T, I>::set(coins.coin, new_supply);
Self::deposit_event(Event::Mint { to, balance }); Self::emit_event(Event::Mint { to: to.into(), coins });
Ok(()) Ok(())
} }
@@ -238,12 +218,12 @@ mod pallet {
Ok(()) Ok(())
} }
/// Transfer `balance` from `from` to `to`. /// Transfer `coins` from `from` to `to`.
pub fn transfer_fn(from: Public, to: Public, balance: Balance) -> Result<(), Error<T, I>> { pub fn transfer_fn(from: Public, to: Public, coins: Balance) -> Result<(), Error<T, I>> {
// update balances of accounts // update balances of accounts
Self::decrease_balance_internal(from, balance)?; Self::decrease_balance_internal(from, coins)?;
Self::increase_balance_internal(to, balance)?; Self::increase_balance_internal(to, coins)?;
Self::deposit_event(Event::Transfer { from, to, balance }); Self::emit_event(Event::Transfer { from: from.into(), to: to.into(), coins });
Ok(()) Ok(())
} }
} }
@@ -253,19 +233,19 @@ mod pallet {
/// Transfer `balance` from the signer to `to`. /// Transfer `balance` from the signer to `to`.
#[pallet::call_index(0)] #[pallet::call_index(0)]
#[pallet::weight((0, DispatchClass::Normal))] // TODO #[pallet::weight((0, DispatchClass::Normal))] // TODO
pub fn transfer(origin: OriginFor<T>, to: Public, balance: Balance) -> DispatchResult { pub fn transfer(origin: OriginFor<T>, to: Public, coins: Balance) -> DispatchResult {
let from = ensure_signed(origin)?; let from = ensure_signed(origin)?;
Self::transfer_fn(from, to, balance)?; Self::transfer_fn(from, to, coins)?;
Ok(()) Ok(())
} }
/// Burn `balance` from the signer. /// Burn `coins` from the signer.
#[pallet::call_index(1)] #[pallet::call_index(1)]
#[pallet::weight((0, DispatchClass::Normal))] // TODO #[pallet::weight((0, DispatchClass::Normal))] // TODO
pub fn burn(origin: OriginFor<T>, balance: Balance) -> DispatchResult { pub fn burn(origin: OriginFor<T>, coins: Balance) -> DispatchResult {
let from = ensure_signed(origin)?; let from = ensure_signed(origin)?;
Self::burn_internal(from, balance)?; Self::burn_internal(from, coins)?;
Self::deposit_event(Event::Burn { from, balance }); Self::emit_event(Event::Burn { from: from.into(), coins });
Ok(()) Ok(())
} }
@@ -283,7 +263,7 @@ mod pallet {
let from = ensure_signed(origin)?; let from = ensure_signed(origin)?;
Self::burn_internal(from, instruction.balance.into())?; Self::burn_internal(from, instruction.balance.into())?;
Self::deposit_event(Event::BurnWithInstruction { from, instruction }); Self::emit_event(Event::BurnWithInstruction { from: from.into(), instruction });
Ok(()) Ok(())
} }
} }

View File

@@ -1,8 +1,8 @@
//! Test environment for Coins pallet. //! Test environment for Coins pallet.
use sp_runtime::BuildStorage; use borsh::BorshDeserialize;
use frame_support::{derive_impl, construct_runtime}; use frame_support::{sp_runtime::BuildStorage, derive_impl, construct_runtime};
use crate::{self as coins, CoinsInstance}; use crate::{self as coins, CoinsInstance};
@@ -10,6 +10,7 @@ construct_runtime!(
pub enum Test pub enum Test
{ {
System: frame_system, System: frame_system,
Core: serai_core_pallet,
Coins: coins::<CoinsInstance>, Coins: coins::<CoinsInstance>,
} }
); );
@@ -17,15 +18,28 @@ construct_runtime!(
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test { impl frame_system::Config for Test {
type AccountId = sp_core::sr25519::Public; type AccountId = sp_core::sr25519::Public;
type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>; type Lookup = frame_support::sp_runtime::traits::IdentityLookup<Self::AccountId>;
type Block = frame_system::mocking::MockBlock<Test>; type Block = frame_system::mocking::MockBlock<Test>;
} }
impl serai_core_pallet::Config for Test {}
impl crate::Config<CoinsInstance> for Test { impl crate::Config<CoinsInstance> for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = crate::AlwaysAllowMint; type AllowMint = crate::AlwaysAllowMint;
} }
impl TryFrom<RuntimeEvent> for serai_abi::Event {
type Error = ();
fn try_from(event: RuntimeEvent) -> Result<serai_abi::Event, ()> {
match event {
RuntimeEvent::Core(serai_core_pallet::Event::Event(event)) => {
Ok(serai_abi::Event::deserialize_reader(&mut event.as_slice()).unwrap())
}
_ => Err(()),
}
}
}
pub(crate) fn new_test_ext() -> sp_io::TestExternalities { pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap(); let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();

View File

@@ -1,15 +1,17 @@
use sp_core::{Pair as _, sr25519::Pair}; use sp_core::{Pair as _, sr25519::Pair};
use frame_system::RawOrigin; use frame_system::RawOrigin;
use serai_primitives::{coin::*, balance::*, address::*, instructions::*}; use serai_abi::primitives::{coin::*, balance::*, address::*, instructions::*};
use crate::mock::*; use crate::mock::*;
pub type CoinsEvent = crate::Event<Test, crate::CoinsInstance>; pub type CoinsEvent = serai_abi::coins::Event;
#[test] #[test]
fn mint() { fn mint() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
Core::start_transaction();
// minting u64::MAX should work // minting u64::MAX should work
let coin = Coin::Serai; let coin = Coin::Serai;
let to = Pair::generate().0.public(); let to = Pair::generate().0.public();
@@ -25,10 +27,10 @@ fn mint() {
assert_eq!(Coins::supply(coin), balance.amount); assert_eq!(Coins::supply(coin), balance.amount);
// test events // test events
let mint_events = System::events() let mint_events = Core::events()
.iter() .iter()
.filter_map(|event| { .filter_map(|event| {
if let RuntimeEvent::Coins(e) = &event.event { if let serai_abi::Event::Coins(e) = &event {
if matches!(e, CoinsEvent::Mint { .. }) { if matches!(e, CoinsEvent::Mint { .. }) {
Some(e.clone()) Some(e.clone())
} else { } else {
@@ -40,13 +42,15 @@ fn mint() {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(mint_events, vec![CoinsEvent::Mint { to, balance }]); assert_eq!(mint_events, vec![CoinsEvent::Mint { to: to.into(), coins: balance }]);
}) })
} }
#[test] #[test]
fn burn_with_instruction() { fn burn_with_instruction() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
Core::start_transaction();
// mint some coin // mint some coin
let coin = Coin::External(ExternalCoin::Bitcoin); let coin = Coin::External(ExternalCoin::Bitcoin);
let to = Pair::generate().0.public(); let to = Pair::generate().0.public();
@@ -76,10 +80,10 @@ fn burn_with_instruction() {
assert_eq!(Coins::balance(to, coin), Amount(0)); assert_eq!(Coins::balance(to, coin), Amount(0));
assert_eq!(Coins::supply(coin), Amount(0)); assert_eq!(Coins::supply(coin), Amount(0));
let burn_events = System::events() let burn_events = Core::events()
.iter() .iter()
.filter_map(|event| { .filter_map(|event| {
if let RuntimeEvent::Coins(e) = &event.event { if let serai_abi::Event::Coins(e) = &event {
if matches!(e, CoinsEvent::BurnWithInstruction { .. }) { if matches!(e, CoinsEvent::BurnWithInstruction { .. }) {
Some(e.clone()) Some(e.clone())
} else { } else {
@@ -91,13 +95,15 @@ fn burn_with_instruction() {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(burn_events, vec![CoinsEvent::BurnWithInstruction { from: to, instruction }]); assert_eq!(burn_events, vec![CoinsEvent::BurnWithInstruction { from: to.into(), instruction }]);
}) })
} }
#[test] #[test]
fn transfer() { fn transfer() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
Core::start_transaction();
// mint some coin // mint some coin
let coin = Coin::External(ExternalCoin::Bitcoin); let coin = Coin::External(ExternalCoin::Bitcoin);
let from = Pair::generate().0.public(); let from = Pair::generate().0.public();

View File

@@ -12,9 +12,6 @@ rust-version = "1.85"
all-features = true all-features = true
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-machete]
ignored = ["scale"]
[lints] [lints]
workspace = true workspace = true
@@ -24,7 +21,6 @@ borsh = { version = "1", default-features = false, features = ["derive", "de_str
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
@@ -37,7 +33,6 @@ std = [
"scale/std", "scale/std",
"sp-core/std", "sp-core/std",
"sp-io/std",
"frame-system/std", "frame-system/std",
"frame-support/std", "frame-support/std",
@@ -50,7 +45,6 @@ runtime-benchmarks = [
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
] ]
# TODO try-runtime = ["serai-abi/try-runtime"]
try-runtime = []
default = ["std"] default = ["std"]

View File

@@ -5,18 +5,20 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use frame_support::pallet_prelude::*; extern crate alloc;
use serai_abi::{
primitives::{prelude::*, merkle::IncrementalUnbalancedMerkleTree as Iumt},
*,
};
mod iumt; mod iumt;
pub use iumt::*; pub use iumt::*;
#[expect(clippy::cast_possible_truncation)]
#[frame_support::pallet] #[frame_support::pallet]
mod pallet { pub mod pallet {
use alloc::vec::Vec;
use frame_support::pallet_prelude::*;
use serai_abi::primitives::{prelude::*, merkle::IncrementalUnbalancedMerkleTree as Iumt};
use super::*; use super::*;
/// The set of all blocks prior added to the blockchain. /// The set of all blocks prior added to the blockchain.
@@ -41,8 +43,8 @@ mod pallet {
pub(super) type TransactionEvents<T: Config> = StorageValue<_, Iumt, OptionQuery>; pub(super) type TransactionEvents<T: Config> = StorageValue<_, Iumt, OptionQuery>;
pub(super) type TransactionEventsMerkle<T> = IncrementalUnbalancedMerkleTree< pub(super) type TransactionEventsMerkle<T> = IncrementalUnbalancedMerkleTree<
TransactionEvents<T>, TransactionEvents<T>,
TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG, { serai_abi::TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG },
TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG, { serai_abi::TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG },
>; >;
/// The roots of the Merkle trees of each transaction's events. /// The roots of the Merkle trees of each transaction's events.
#[pallet::storage] #[pallet::storage]
@@ -50,14 +52,22 @@ mod pallet {
pub(super) type BlockEventsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>; pub(super) type BlockEventsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
pub(super) type BlockEventsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree< pub(super) type BlockEventsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
BlockEventsCommitment<T>, BlockEventsCommitment<T>,
EVENTS_COMMITMENT_BRANCH_TAG, { serai_abi::EVENTS_COMMITMENT_BRANCH_TAG },
EVENTS_COMMITMENT_LEAF_TAG, { serai_abi::EVENTS_COMMITMENT_LEAF_TAG },
>; >;
/// A mapping from an account to its next nonce. /// A mapping from an account to its next nonce.
#[pallet::storage] #[pallet::storage]
type NextNonce<T: Config> = StorageMap<_, Blake2_128Concat, SeraiAddress, T::Nonce, ValueQuery>; type NextNonce<T: Config> = StorageMap<_, Blake2_128Concat, SeraiAddress, T::Nonce, ValueQuery>;
/// Mapping from Serai's events to Substrate's.
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// An event from Serai.
Event(Vec<u8>),
}
#[pallet::config] #[pallet::config]
pub trait Config: frame_system::Config<Hash: Into<[u8; 32]>> {} pub trait Config: frame_system::Config<Hash: Into<[u8; 32]>> {}
@@ -94,13 +104,14 @@ mod pallet {
pub fn start_transaction() { pub fn start_transaction() {
TransactionEventsMerkle::<T>::new_expecting_none(); TransactionEventsMerkle::<T>::new_expecting_none();
} }
/// Emit an event. /// Emit an event.
// TODO: Have this called pub fn emit_event(event: impl Into<serai_abi::Event>) {
pub fn emit_event(event: impl TryInto<serai_abi::Event>) { let event = event.into();
if let Ok(event) = event.try_into() { TransactionEventsMerkle::<T>::append(&event);
TransactionEventsMerkle::<T>::append(&event); Self::deposit_event(Event::Event(borsh::to_vec(&event).unwrap()));
}
} }
/// End execution of a transaction. /// End execution of a transaction.
pub fn end_transaction(transaction_hash: [u8; 32]) { pub fn end_transaction(transaction_hash: [u8; 32]) {
BlockTransactionsCommitmentMerkle::<T>::append(&transaction_hash); BlockTransactionsCommitmentMerkle::<T>::append(&transaction_hash);
@@ -111,6 +122,19 @@ mod pallet {
// commitment // commitment
BlockEventsCommitmentMerkle::<T>::append(&(&transaction_hash, &transaction_events_root)); BlockEventsCommitmentMerkle::<T>::append(&(&transaction_hash, &transaction_events_root));
} }
/// Fetch all of Serai's events.
///
/// This MUST only be used for testing purposes.
pub fn events() -> Vec<serai_abi::Event>
where
serai_abi::Event: TryFrom<T::RuntimeEvent>,
{
frame_system::Pallet::<T>::events()
.into_iter()
.filter_map(|e| serai_abi::Event::try_from(e.event).ok())
.collect()
}
} }
} }
pub use pallet::*; pub use pallet::*;
@@ -119,6 +143,8 @@ pub use pallet::*;
pub struct StartOfBlock<T: Config>(PhantomData<T>); pub struct StartOfBlock<T: Config>(PhantomData<T>);
impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> { impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
fn pre_inherents() { fn pre_inherents() {
use frame_support::pallet_prelude::Zero;
if frame_system::Pallet::<T>::block_number().is_zero() { if frame_system::Pallet::<T>::block_number().is_zero() {
BlocksCommitmentMerkle::<T>::new_expecting_none(); BlocksCommitmentMerkle::<T>::new_expecting_none();
} else { } else {
@@ -137,6 +163,7 @@ impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
pub struct EndOfBlock<T: Config>(PhantomData<T>); pub struct EndOfBlock<T: Config>(PhantomData<T>);
impl<T: Config> frame_support::traits::PostTransactions for EndOfBlock<T> { impl<T: Config> frame_support::traits::PostTransactions for EndOfBlock<T> {
fn post_transactions() { fn post_transactions() {
use serai_abi::SeraiExecutionDigest;
frame_system::Pallet::<T>::deposit_log( frame_system::Pallet::<T>::deposit_log(
frame_support::sp_runtime::generic::DigestItem::Consensus( frame_support::sp_runtime::generic::DigestItem::Consensus(
SeraiExecutionDigest::CONSENSUS_ID, SeraiExecutionDigest::CONSENSUS_ID,

View File

@@ -18,8 +18,6 @@ ignored = ["scale"]
workspace = true workspace = true
[dependencies] [dependencies]
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
@@ -43,7 +41,6 @@ substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sd
[features] [features]
std = [ std = [
"borsh/std",
"scale/std", "scale/std",
"sp-core/std", "sp-core/std",

View File

@@ -158,11 +158,9 @@ impl From<serai_abi::Call> for RuntimeCall {
use serai_abi::coins::Call; use serai_abi::coins::Call;
match call { match call {
Call::transfer { to, coins } => { Call::transfer { to, coins } => {
RuntimeCall::Coins(serai_coins_pallet::Call::transfer { to: to.into(), balance: coins }) RuntimeCall::Coins(serai_coins_pallet::Call::transfer { to: to.into(), coins })
}
Call::burn { coins } => {
RuntimeCall::Coins(serai_coins_pallet::Call::burn { balance: coins })
} }
Call::burn { coins } => RuntimeCall::Coins(serai_coins_pallet::Call::burn { coins }),
Call::burn_with_instruction { instruction } => { Call::burn_with_instruction { instruction } => {
RuntimeCall::Coins(serai_coins_pallet::Call::burn_with_instruction { instruction }) RuntimeCall::Coins(serai_coins_pallet::Call::burn_with_instruction { instruction })
} }
@@ -195,7 +193,7 @@ impl From<serai_abi::Call> for RuntimeCall {
Call::transfer_liquidity { to, liquidity_tokens } => { Call::transfer_liquidity { to, liquidity_tokens } => {
RuntimeCall::LiquidityTokens(serai_coins_pallet::Call::transfer { RuntimeCall::LiquidityTokens(serai_coins_pallet::Call::transfer {
to: to.into(), to: to.into(),
balance: liquidity_tokens.into(), coins: liquidity_tokens.into(),
}) })
} }
Call::add_liquidity { .. } | Call::add_liquidity { .. } |

View File

@@ -22,7 +22,6 @@ workspace = true
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false } frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
@@ -36,7 +35,6 @@ std = [
"scale/std", "scale/std",
"sp-core/std", "sp-core/std",
"sp-io/std",
"frame-system/std", "frame-system/std",
"frame-support/std", "frame-support/std",