mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-22 19:49:22 +00:00
Use the serai_abi::Call in the actual Transaction type
We prior required they had the same encoding, yet this ensures they do by making them one and the same. This does require an large, ugly, From/TryInto block which is deemed preferable for moving this more and more into syntax (from semantics). Further improvements (notably re: Extra) is possible, and this already lets us strip some members from the Call enum.
This commit is contained in:
parent
2a05cf3225
commit
41ce5b1738
23 changed files with 677 additions and 211 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -8195,6 +8195,7 @@ dependencies = [
|
|||
"pallet-transaction-payment-rpc-runtime-api",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"serai-abi",
|
||||
"serai-coins-pallet",
|
||||
"serai-dex-pallet",
|
||||
"serai-in-instructions-pallet",
|
||||
|
|
|
@ -133,7 +133,13 @@ mod impl_pst_for_serai {
|
|||
key_pair: KeyPair,
|
||||
signature: Signature,
|
||||
) {
|
||||
let tx = SeraiValidatorSets::set_keys(set.network, removed, key_pair, signature);
|
||||
// TODO: BoundedVec as an arg to avoid this expect
|
||||
let tx = SeraiValidatorSets::set_keys(
|
||||
set.network,
|
||||
removed.try_into().expect("removing more than allowed"),
|
||||
key_pair,
|
||||
signature,
|
||||
);
|
||||
async fn check(serai: SeraiValidatorSets<'_>, set: ValidatorSet, (): ()) -> bool {
|
||||
if matches!(serai.keys(set).await, Ok(Some(_))) {
|
||||
log::info!("another coordinator set key pair for {:?}", set);
|
||||
|
|
|
@ -16,27 +16,48 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", features = ["derive"] }
|
||||
scale-info = { version = "2", features = ["derive"] }
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2", default-features = false, features = ["derive"] }
|
||||
|
||||
borsh = { version = "1", features = ["derive", "de_strict_order"], optional = true }
|
||||
serde = { version = "1", features = ["derive", "alloc"], optional = true }
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
|
||||
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/substrate" }
|
||||
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-consensus-babe = { git = "https://github.com/serai-dex/substrate" }
|
||||
sp-consensus-grandpa = { git = "https://github.com/serai-dex/substrate" }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-consensus-grandpa = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
||||
serai-primitives = { path = "../primitives", version = "0.1" }
|
||||
serai-coins-primitives = { path = "../coins/primitives", version = "0.1" }
|
||||
serai-validator-sets-primitives = { path = "../validator-sets/primitives", version = "0.1" }
|
||||
serai-in-instructions-primitives = { path = "../in-instructions/primitives", version = "0.1" }
|
||||
serai-signals-primitives = { path = "../signals/primitives", version = "0.1" }
|
||||
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
||||
frame-support = { git = "https://github.com/serai-dex/substrate" }
|
||||
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
||||
serai-coins-primitives = { path = "../coins/primitives", version = "0.1", default-features = false }
|
||||
serai-validator-sets-primitives = { path = "../validator-sets/primitives", version = "0.1", default-features = false }
|
||||
serai-in-instructions-primitives = { path = "../in-instructions/primitives", version = "0.1", default-features = false }
|
||||
serai-signals-primitives = { path = "../signals/primitives", version = "0.1", default-features = false }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"scale/std",
|
||||
"scale-info/std",
|
||||
|
||||
"borsh?/std",
|
||||
"serde?/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
|
||||
"sp-consensus-babe/std",
|
||||
"sp-consensus-grandpa/std",
|
||||
|
||||
"frame-support/std",
|
||||
|
||||
"serai-primitives/std",
|
||||
"serai-coins-primitives/std",
|
||||
"serai-validator-sets-primitives/std",
|
||||
"serai-in-instructions-primitives/std",
|
||||
"serai-signals-primitives/std",
|
||||
]
|
||||
borsh = [
|
||||
"dep:borsh",
|
||||
"serai-primitives/borsh",
|
||||
|
@ -53,3 +74,4 @@ serde = [
|
|||
"serai-in-instructions-primitives/serde",
|
||||
"serai-signals-primitives/serde",
|
||||
]
|
||||
default = ["std"]
|
||||
|
|
|
@ -4,7 +4,7 @@ use serai_primitives::{Header, SeraiAddress};
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct ReportEquivocation {
|
||||
pub equivocation_proof: Box<EquivocationProof<Header>>,
|
||||
pub equivocation_proof: alloc::boxed::Box<EquivocationProof<Header>>,
|
||||
pub key_owner_proof: SeraiAddress,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ use primitives::OutInstructionWithBalance;
|
|||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
transfer { to: SeraiAddress, balance: Balance },
|
||||
burn { balance: Balance },
|
||||
|
@ -14,7 +15,17 @@ pub enum Call {
|
|||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum LiquidityTokensCall {
|
||||
transfer { to: SeraiAddress, balance: Balance },
|
||||
burn { balance: Balance },
|
||||
}
|
||||
|
||||
#[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))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
Mint { to: SeraiAddress, balance: Balance },
|
||||
Burn { from: SeraiAddress, balance: Balance },
|
||||
|
|
|
@ -6,7 +6,8 @@ type PoolId = Coin;
|
|||
type MaxSwapPathLength = sp_core::ConstU32<3>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
add_liquidity {
|
||||
coin: Coin,
|
||||
|
@ -38,7 +39,8 @@ pub enum Call {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
PoolCreated {
|
||||
pool_id: PoolId,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
use sp_consensus_grandpa::EquivocationProof;
|
||||
|
||||
use serai_primitives::{BlockNumber, SeraiAddress};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct ReportEquivocation {
|
||||
pub equivocation_proof: Box<EquivocationProof<[u8; 32], BlockNumber>>,
|
||||
pub equivocation_proof: alloc::boxed::Box<EquivocationProof<[u8; 32], BlockNumber>>,
|
||||
pub key_owner_proof: SeraiAddress,
|
||||
}
|
||||
|
||||
|
@ -15,10 +16,10 @@ pub enum Call {
|
|||
}
|
||||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
NewAuthorities { authority_set: Vec<(SeraiAddress, u64)> },
|
||||
NewAuthorities { authority_set: BoundedVec<(SeraiAddress, u64), ConstU32<0>> },
|
||||
// TODO: Remove these
|
||||
Paused,
|
||||
Resumed,
|
||||
|
|
|
@ -5,14 +5,16 @@ use primitives::SignedBatch;
|
|||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
execute_batch { batch: SignedBatch },
|
||||
}
|
||||
|
||||
#[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))]
|
||||
#[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 },
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub use serai_primitives as primitives;
|
||||
|
||||
pub mod system;
|
||||
|
||||
pub mod timestamp;
|
||||
|
@ -14,15 +21,13 @@ pub mod signals;
|
|||
pub mod babe;
|
||||
pub mod grandpa;
|
||||
|
||||
pub use serai_primitives as primitives;
|
||||
pub mod tx;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Call {
|
||||
System,
|
||||
Timestamp(timestamp::Call),
|
||||
TransactionPayment,
|
||||
Coins(coins::Call),
|
||||
LiquidityTokens(coins::Call),
|
||||
LiquidityTokens(coins::LiquidityTokensCall),
|
||||
Dex(dex::Call),
|
||||
ValidatorSets(validator_sets::Call),
|
||||
InInstructions(in_instructions::Call),
|
||||
|
@ -53,16 +58,20 @@ pub enum Event {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub struct Extra {
|
||||
pub era: sp_runtime::generic::Era,
|
||||
pub nonce: scale::Compact<u32>,
|
||||
pub tip: scale::Compact<u64>,
|
||||
#[codec(compact)]
|
||||
pub nonce: u32,
|
||||
#[codec(compact)]
|
||||
pub tip: u64,
|
||||
}
|
||||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub struct SignedPayloadExtra {
|
||||
pub spec_version: u32,
|
||||
pub tx_version: u32,
|
||||
|
@ -70,4 +79,4 @@ pub struct SignedPayloadExtra {
|
|||
pub mortality_checkpoint: [u8; 32],
|
||||
}
|
||||
|
||||
pub type Transaction = primitives::Transaction<Call, Extra>;
|
||||
pub type Transaction = tx::Transaction<Call, Extra>;
|
||||
|
|
|
@ -7,7 +7,8 @@ use primitives::SignalId;
|
|||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
register_retirement_signal { in_favor_of: [u8; 32] },
|
||||
revoke_retirement_signal { retirement_signal_id: [u8; 32] },
|
||||
|
@ -18,7 +19,8 @@ pub enum Call {
|
|||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
RetirementSignalRegistered {
|
||||
signal_id: [u8; 32],
|
||||
|
|
|
@ -3,7 +3,6 @@ use frame_support::dispatch::{DispatchInfo, DispatchError};
|
|||
use serai_primitives::SeraiAddress;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
ExtrinsicSuccess { dispatch_info: DispatchInfo },
|
||||
ExtrinsicFailed { dispatch_error: DispatchError, dispatch_info: DispatchInfo },
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
set { now: scale::Compact<u64> },
|
||||
set {
|
||||
#[codec(compact)]
|
||||
now: u64,
|
||||
},
|
||||
}
|
||||
|
|
183
substrate/abi/src/tx.rs
Normal file
183
substrate/abi/src/tx.rs
Normal file
|
@ -0,0 +1,183 @@
|
|||
use scale::Encode;
|
||||
|
||||
use sp_core::sr25519::{Public, Signature};
|
||||
use sp_runtime::traits::Verify;
|
||||
|
||||
use serai_primitives::SeraiAddress;
|
||||
|
||||
use frame_support::dispatch::GetDispatchInfo;
|
||||
|
||||
pub trait TransactionMember:
|
||||
Clone + PartialEq + Eq + core::fmt::Debug + scale::Encode + scale::Decode + scale_info::TypeInfo
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Clone
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ core::fmt::Debug
|
||||
+ scale::Encode
|
||||
+ scale::Decode
|
||||
+ scale_info::TypeInfo,
|
||||
> TransactionMember for T
|
||||
{
|
||||
}
|
||||
|
||||
type TransactionEncodeAs<'a, Extra> =
|
||||
(&'a crate::Call, &'a Option<(SeraiAddress, Signature, Extra)>);
|
||||
type TransactionDecodeAs<Extra> = (crate::Call, Option<(SeraiAddress, Signature, Extra)>);
|
||||
|
||||
// We use our own Transaction struct, over UncheckedExtrinsic, for more control, a bit more
|
||||
// simplicity, and in order to be immune to https://github.com/paritytech/polkadot-sdk/issues/2947
|
||||
#[allow(private_bounds)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Transaction<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> {
|
||||
call: crate::Call,
|
||||
mapped_call: Call,
|
||||
signature: Option<(SeraiAddress, Signature, Extra)>,
|
||||
}
|
||||
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
Transaction<Call, Extra>
|
||||
{
|
||||
pub fn new(call: crate::Call, signature: Option<(SeraiAddress, Signature, Extra)>) -> Self {
|
||||
Self { call: call.clone(), mapped_call: call.into(), signature }
|
||||
}
|
||||
|
||||
pub fn call(&self) -> &crate::Call {
|
||||
&self.call
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
scale::Encode for Transaction<Call, Extra>
|
||||
{
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
let tx: TransactionEncodeAs<Extra> = (&self.call, &self.signature);
|
||||
tx.using_encoded(f)
|
||||
}
|
||||
}
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
scale::Decode for Transaction<Call, Extra>
|
||||
{
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
let (call, signature) = TransactionDecodeAs::decode(input)?;
|
||||
let mapped_call = Call::from(call.clone());
|
||||
Ok(Self { call, mapped_call, signature })
|
||||
}
|
||||
}
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
scale_info::TypeInfo for Transaction<Call, Extra>
|
||||
{
|
||||
type Identity = TransactionDecodeAs<Extra>;
|
||||
|
||||
// Define the type info as the info of the type equivalent to what we encode as
|
||||
fn type_info() -> scale_info::Type {
|
||||
TransactionDecodeAs::<Extra>::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod _serde {
|
||||
use scale::Encode;
|
||||
use serde::{ser::*, de::*};
|
||||
use super::*;
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
Serialize for Transaction<Call, Extra>
|
||||
{
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let encoded = self.encode();
|
||||
serializer.serialize_bytes(&encoded)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
impl<
|
||||
'a,
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> Deserialize<'a> for Transaction<Call, Extra>
|
||||
{
|
||||
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
|
||||
let bytes = sp_core::bytes::deserialize(de)?;
|
||||
<Self as scale::Decode>::decode(&mut &bytes[..])
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid transaction: {e}")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + TryInto<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> sp_runtime::traits::Extrinsic for Transaction<Call, Extra>
|
||||
{
|
||||
type Call = Call;
|
||||
type SignaturePayload = (SeraiAddress, Signature, Extra);
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.signature.is_some())
|
||||
}
|
||||
fn new(call: Call, signature: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(Self { call: call.clone().try_into().ok()?, mapped_call: call, signature })
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + TryInto<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> frame_support::traits::ExtrinsicCall for Transaction<Call, Extra>
|
||||
{
|
||||
fn call(&self) -> &Call {
|
||||
&self.mapped_call
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember + sp_runtime::traits::SignedExtension,
|
||||
> sp_runtime::traits::ExtrinsicMetadata for Transaction<Call, Extra>
|
||||
{
|
||||
type SignedExtensions = Extra;
|
||||
|
||||
const VERSION: u8 = 0;
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + GetDispatchInfo,
|
||||
Extra: 'static + TransactionMember,
|
||||
> GetDispatchInfo for Transaction<Call, Extra>
|
||||
{
|
||||
fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
|
||||
self.mapped_call.get_dispatch_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember + sp_runtime::traits::SignedExtension,
|
||||
> sp_runtime::traits::BlindCheckable for Transaction<Call, Extra>
|
||||
{
|
||||
type Checked = sp_runtime::generic::CheckedExtrinsic<Public, Call, Extra>;
|
||||
|
||||
fn check(
|
||||
self,
|
||||
) -> Result<Self::Checked, sp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(match self.signature {
|
||||
Some((signer, signature, extra)) => {
|
||||
if !signature.verify(
|
||||
(&self.call, &extra, extra.additional_signed()?).encode().as_slice(),
|
||||
&signer.into(),
|
||||
) {
|
||||
Err(sp_runtime::transaction_validity::InvalidTransaction::BadProof)?
|
||||
}
|
||||
|
||||
sp_runtime::generic::CheckedExtrinsic {
|
||||
signed: Some((signer.into(), extra)),
|
||||
function: self.mapped_call,
|
||||
}
|
||||
}
|
||||
None => sp_runtime::generic::CheckedExtrinsic { signed: None, function: self.mapped_call },
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use sp_core::{ConstU32, bounded_vec::BoundedVec};
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
|
||||
pub use serai_validator_sets_primitives as primitives;
|
||||
|
||||
|
@ -6,11 +6,12 @@ use serai_primitives::*;
|
|||
use serai_validator_sets_primitives::*;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
set_keys {
|
||||
network: NetworkId,
|
||||
removed_participants: Vec<SeraiAddress>,
|
||||
removed_participants: BoundedVec<SeraiAddress, ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>,
|
||||
key_pair: KeyPair,
|
||||
signature: Signature,
|
||||
},
|
||||
|
@ -35,7 +36,8 @@ pub enum Call {
|
|||
|
||||
#[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))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
NewSet {
|
||||
set: ValidatorSet,
|
||||
|
|
|
@ -3,7 +3,7 @@ use thiserror::Error;
|
|||
use async_lock::RwLock;
|
||||
use simple_request::{hyper, Request, Client};
|
||||
|
||||
use scale::{Compact, Decode, Encode};
|
||||
use scale::{Decode, Encode};
|
||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||
|
||||
pub use sp_core::{
|
||||
|
@ -43,8 +43,8 @@ impl Block {
|
|||
/// Returns the time of this block, set by its producer, in milliseconds since the epoch.
|
||||
pub fn time(&self) -> Result<u64, SeraiError> {
|
||||
for transaction in &self.transactions {
|
||||
if let Call::Timestamp(timestamp::Call::set { now }) = &transaction.call {
|
||||
return Ok(u64::from(*now));
|
||||
if let Call::Timestamp(timestamp::Call::set { now }) = transaction.call() {
|
||||
return Ok(*now);
|
||||
}
|
||||
}
|
||||
Err(SeraiError::InvalidNode("no time was present in block".to_string()))
|
||||
|
@ -162,15 +162,14 @@ impl Serai {
|
|||
}
|
||||
|
||||
fn unsigned(call: Call) -> Transaction {
|
||||
Transaction { call, signature: None }
|
||||
Transaction::new(call, None)
|
||||
}
|
||||
|
||||
pub fn sign(&self, signer: &Pair, call: Call, nonce: u32, tip: u64) -> Transaction {
|
||||
const SPEC_VERSION: u32 = 1;
|
||||
const TX_VERSION: u32 = 1;
|
||||
|
||||
let extra =
|
||||
Extra { era: sp_runtime::generic::Era::Immortal, nonce: Compact(nonce), tip: Compact(tip) };
|
||||
let extra = Extra { era: sp_runtime::generic::Era::Immortal, nonce, tip };
|
||||
let signature_payload = (
|
||||
&call,
|
||||
&extra,
|
||||
|
@ -184,7 +183,7 @@ impl Serai {
|
|||
.encode();
|
||||
let signature = signer.sign(&signature_payload);
|
||||
|
||||
Transaction { call, signature: Some((signer.public().into(), signature, extra)) }
|
||||
Transaction::new(call, Some((signer.public().into(), signature, extra)))
|
||||
}
|
||||
|
||||
pub async fn publish(&self, tx: &Transaction) -> Result<(), SeraiError> {
|
||||
|
|
|
@ -180,7 +180,10 @@ impl<'a> SeraiValidatorSets<'a> {
|
|||
|
||||
pub fn set_keys(
|
||||
network: NetworkId,
|
||||
removed_participants: Vec<SeraiAddress>,
|
||||
removed_participants: sp_runtime::BoundedVec<
|
||||
SeraiAddress,
|
||||
sp_core::ConstU32<{ primitives::MAX_KEY_SHARES_PER_SET / 3 }>,
|
||||
>,
|
||||
key_pair: KeyPair,
|
||||
signature: Signature,
|
||||
) -> Transaction {
|
||||
|
|
|
@ -51,7 +51,12 @@ pub async fn set_keys(serai: &Serai, set: ValidatorSet, key_pair: KeyPair) -> [u
|
|||
// Set the key pair
|
||||
let block = publish_tx(
|
||||
serai,
|
||||
&SeraiValidatorSets::set_keys(set.network, vec![], key_pair.clone(), Signature(sig.to_bytes())),
|
||||
&SeraiValidatorSets::set_keys(
|
||||
set.network,
|
||||
vec![].try_into().unwrap(),
|
||||
key_pair.clone(),
|
||||
Signature(sig.to_bytes()),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -37,9 +37,6 @@ pub use balance::*;
|
|||
mod account;
|
||||
pub use account::*;
|
||||
|
||||
mod tx;
|
||||
pub use tx::*;
|
||||
|
||||
pub type BlockNumber = u64;
|
||||
pub type Header = sp_runtime::generic::Header<BlockNumber, sp_runtime::traits::BlakeTwo256>;
|
||||
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
use scale::Encode;
|
||||
|
||||
use sp_core::sr25519::{Public, Signature};
|
||||
use sp_runtime::traits::Verify;
|
||||
|
||||
use crate::SeraiAddress;
|
||||
|
||||
trait TransactionMember:
|
||||
Clone + PartialEq + Eq + core::fmt::Debug + scale::Encode + scale::Decode + scale_info::TypeInfo
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Clone
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ core::fmt::Debug
|
||||
+ scale::Encode
|
||||
+ scale::Decode
|
||||
+ scale_info::TypeInfo,
|
||||
> TransactionMember for T
|
||||
{
|
||||
}
|
||||
|
||||
// We use our own Transaction struct, over UncheckedExtrinsic, for more control, a bit more
|
||||
// simplicity, and in order to be immune to https://github.com/paritytech/polkadot-sdk/issues/2947
|
||||
#[allow(private_bounds)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct Transaction<Call: TransactionMember, Extra: TransactionMember> {
|
||||
pub call: Call,
|
||||
pub signature: Option<(SeraiAddress, Signature, Extra)>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod _serde {
|
||||
use scale::Encode;
|
||||
use serde::{ser::*, de::*};
|
||||
use super::*;
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> Serialize for Transaction<Call, Extra> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let encoded = self.encode();
|
||||
serializer.serialize_bytes(&encoded)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a, Call: TransactionMember, Extra: TransactionMember> Deserialize<'a>
|
||||
for Transaction<Call, Extra>
|
||||
{
|
||||
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
|
||||
let bytes = sp_core::bytes::deserialize(de)?;
|
||||
scale::Decode::decode(&mut &bytes[..])
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid transaction: {e}")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> sp_runtime::traits::Extrinsic
|
||||
for Transaction<Call, Extra>
|
||||
{
|
||||
type Call = Call;
|
||||
type SignaturePayload = (SeraiAddress, Signature, Extra);
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.signature.is_some())
|
||||
}
|
||||
fn new(call: Call, signature: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(Self { call, signature })
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> frame_support::traits::ExtrinsicCall
|
||||
for Transaction<Call, Extra>
|
||||
{
|
||||
fn call(&self) -> &Call {
|
||||
&self.call
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> sp_runtime::traits::ExtrinsicMetadata
|
||||
for Transaction<Call, Extra>
|
||||
where
|
||||
Extra: sp_runtime::traits::SignedExtension,
|
||||
{
|
||||
type SignedExtensions = Extra;
|
||||
|
||||
const VERSION: u8 = 0;
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> frame_support::dispatch::GetDispatchInfo
|
||||
for Transaction<Call, Extra>
|
||||
where
|
||||
Call: frame_support::dispatch::GetDispatchInfo,
|
||||
{
|
||||
fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
|
||||
self.call.get_dispatch_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> sp_runtime::traits::BlindCheckable
|
||||
for Transaction<Call, Extra>
|
||||
where
|
||||
Extra: sp_runtime::traits::SignedExtension,
|
||||
{
|
||||
type Checked = sp_runtime::generic::CheckedExtrinsic<Public, Call, Extra>;
|
||||
|
||||
fn check(
|
||||
self,
|
||||
) -> Result<Self::Checked, sp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(match self.signature {
|
||||
Some((signer, signature, extra)) => {
|
||||
if !signature.verify(
|
||||
(&self.call, &extra, extra.additional_signed()?).encode().as_slice(),
|
||||
&signer.into(),
|
||||
) {
|
||||
Err(sp_runtime::transaction_validity::InvalidTransaction::BadProof)?
|
||||
}
|
||||
|
||||
sp_runtime::generic::CheckedExtrinsic {
|
||||
signed: Some((signer.into(), extra)),
|
||||
function: self.call,
|
||||
}
|
||||
}
|
||||
None => sp_runtime::generic::CheckedExtrinsic { signed: None, function: self.call },
|
||||
})
|
||||
}
|
||||
}
|
|
@ -49,6 +49,7 @@ frame-executive = { git = "https://github.com/serai-dex/substrate", default-feat
|
|||
frame-benchmarking = { git = "https://github.com/serai-dex/substrate", default-features = false, optional = true }
|
||||
|
||||
serai-primitives = { path = "../primitives", default-features = false }
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["serde"] }
|
||||
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
pallet-authorship = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
@ -102,6 +103,8 @@ std = [
|
|||
"frame-executive/std",
|
||||
|
||||
"serai-primitives/std",
|
||||
"serai-abi/std",
|
||||
"serai-abi/serde",
|
||||
|
||||
"pallet-timestamp/std",
|
||||
"pallet-authorship/std",
|
||||
|
|
363
substrate/runtime/src/abi.rs
Normal file
363
substrate/runtime/src/abi.rs
Normal file
|
@ -0,0 +1,363 @@
|
|||
use core::marker::PhantomData;
|
||||
|
||||
use scale::{Encode, Decode};
|
||||
|
||||
use serai_abi::Call;
|
||||
|
||||
use crate::{
|
||||
Vec,
|
||||
primitives::{PublicKey, SeraiAddress},
|
||||
timestamp, coins, dex,
|
||||
validator_sets::{self, MembershipProof},
|
||||
in_instructions, signals, babe, grandpa, RuntimeCall,
|
||||
};
|
||||
|
||||
impl From<Call> for RuntimeCall {
|
||||
fn from(call: Call) -> RuntimeCall {
|
||||
match call {
|
||||
Call::Timestamp(serai_abi::timestamp::Call::set { now }) => {
|
||||
RuntimeCall::Timestamp(timestamp::Call::set { now })
|
||||
}
|
||||
Call::Coins(coins) => match coins {
|
||||
serai_abi::coins::Call::transfer { to, balance } => {
|
||||
RuntimeCall::Coins(coins::Call::transfer { to: to.into(), balance })
|
||||
}
|
||||
serai_abi::coins::Call::burn { balance } => {
|
||||
RuntimeCall::Coins(coins::Call::burn { balance })
|
||||
}
|
||||
serai_abi::coins::Call::burn_with_instruction { instruction } => {
|
||||
RuntimeCall::Coins(coins::Call::burn_with_instruction { instruction })
|
||||
}
|
||||
},
|
||||
Call::LiquidityTokens(lt) => match lt {
|
||||
serai_abi::coins::LiquidityTokensCall::transfer { to, balance } => {
|
||||
RuntimeCall::LiquidityTokens(coins::Call::transfer { to: to.into(), balance })
|
||||
}
|
||||
serai_abi::coins::LiquidityTokensCall::burn { balance } => {
|
||||
RuntimeCall::LiquidityTokens(coins::Call::burn { balance })
|
||||
}
|
||||
},
|
||||
Call::Dex(dex) => match dex {
|
||||
serai_abi::dex::Call::add_liquidity {
|
||||
coin,
|
||||
coin_desired,
|
||||
sri_desired,
|
||||
coin_min,
|
||||
sri_min,
|
||||
mint_to,
|
||||
} => RuntimeCall::Dex(dex::Call::add_liquidity {
|
||||
coin,
|
||||
coin_desired,
|
||||
sri_desired,
|
||||
coin_min,
|
||||
sri_min,
|
||||
mint_to: mint_to.into(),
|
||||
}),
|
||||
serai_abi::dex::Call::remove_liquidity {
|
||||
coin,
|
||||
lp_token_burn,
|
||||
coin_min_receive,
|
||||
sri_min_receive,
|
||||
withdraw_to,
|
||||
} => RuntimeCall::Dex(dex::Call::remove_liquidity {
|
||||
coin,
|
||||
lp_token_burn,
|
||||
coin_min_receive,
|
||||
sri_min_receive,
|
||||
withdraw_to: withdraw_to.into(),
|
||||
}),
|
||||
serai_abi::dex::Call::swap_exact_tokens_for_tokens {
|
||||
path,
|
||||
amount_in,
|
||||
amount_out_min,
|
||||
send_to,
|
||||
} => RuntimeCall::Dex(dex::Call::swap_exact_tokens_for_tokens {
|
||||
path,
|
||||
amount_in,
|
||||
amount_out_min,
|
||||
send_to: send_to.into(),
|
||||
}),
|
||||
serai_abi::dex::Call::swap_tokens_for_exact_tokens {
|
||||
path,
|
||||
amount_out,
|
||||
amount_in_max,
|
||||
send_to,
|
||||
} => RuntimeCall::Dex(dex::Call::swap_tokens_for_exact_tokens {
|
||||
path,
|
||||
amount_out,
|
||||
amount_in_max,
|
||||
send_to: send_to.into(),
|
||||
}),
|
||||
},
|
||||
Call::ValidatorSets(vs) => match vs {
|
||||
serai_abi::validator_sets::Call::set_keys {
|
||||
network,
|
||||
removed_participants,
|
||||
key_pair,
|
||||
signature,
|
||||
} => RuntimeCall::ValidatorSets(validator_sets::Call::set_keys {
|
||||
network,
|
||||
removed_participants: <_>::try_from(
|
||||
removed_participants.into_iter().map(PublicKey::from).collect::<Vec<_>>(),
|
||||
)
|
||||
.unwrap(),
|
||||
key_pair,
|
||||
signature,
|
||||
}),
|
||||
serai_abi::validator_sets::Call::report_slashes { network, slashes, signature } => {
|
||||
RuntimeCall::ValidatorSets(validator_sets::Call::report_slashes {
|
||||
network,
|
||||
slashes: <_>::try_from(
|
||||
slashes
|
||||
.into_iter()
|
||||
.map(|(addr, slash)| (PublicKey::from(addr), slash))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.unwrap(),
|
||||
signature,
|
||||
})
|
||||
}
|
||||
serai_abi::validator_sets::Call::allocate { network, amount } => {
|
||||
RuntimeCall::ValidatorSets(validator_sets::Call::allocate { network, amount })
|
||||
}
|
||||
serai_abi::validator_sets::Call::deallocate { network, amount } => {
|
||||
RuntimeCall::ValidatorSets(validator_sets::Call::deallocate { network, amount })
|
||||
}
|
||||
serai_abi::validator_sets::Call::claim_deallocation { network, session } => {
|
||||
RuntimeCall::ValidatorSets(validator_sets::Call::claim_deallocation { network, session })
|
||||
}
|
||||
},
|
||||
Call::InInstructions(ii) => match ii {
|
||||
serai_abi::in_instructions::Call::execute_batch { batch } => {
|
||||
RuntimeCall::InInstructions(in_instructions::Call::execute_batch { batch })
|
||||
}
|
||||
},
|
||||
Call::Signals(signals) => match signals {
|
||||
serai_abi::signals::Call::register_retirement_signal { in_favor_of } => {
|
||||
RuntimeCall::Signals(signals::Call::register_retirement_signal { in_favor_of })
|
||||
}
|
||||
serai_abi::signals::Call::revoke_retirement_signal { retirement_signal_id } => {
|
||||
RuntimeCall::Signals(signals::Call::revoke_retirement_signal { retirement_signal_id })
|
||||
}
|
||||
serai_abi::signals::Call::favor { signal_id, for_network } => {
|
||||
RuntimeCall::Signals(signals::Call::favor { signal_id, for_network })
|
||||
}
|
||||
serai_abi::signals::Call::revoke_favor { signal_id, for_network } => {
|
||||
RuntimeCall::Signals(signals::Call::revoke_favor { signal_id, for_network })
|
||||
}
|
||||
serai_abi::signals::Call::stand_against { signal_id, for_network } => {
|
||||
RuntimeCall::Signals(signals::Call::stand_against { signal_id, for_network })
|
||||
}
|
||||
},
|
||||
Call::Babe(babe) => match babe {
|
||||
serai_abi::babe::Call::report_equivocation(report) => {
|
||||
RuntimeCall::Babe(babe::Call::report_equivocation {
|
||||
// TODO: Find a better way to go from Proof<[u8; 32]> to Proof<H256>
|
||||
equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice())
|
||||
.unwrap(),
|
||||
key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData),
|
||||
})
|
||||
}
|
||||
serai_abi::babe::Call::report_equivocation_unsigned(report) => {
|
||||
RuntimeCall::Babe(babe::Call::report_equivocation_unsigned {
|
||||
// TODO: Find a better way to go from Proof<[u8; 32]> to Proof<H256>
|
||||
equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice())
|
||||
.unwrap(),
|
||||
key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData),
|
||||
})
|
||||
}
|
||||
},
|
||||
Call::Grandpa(grandpa) => match grandpa {
|
||||
serai_abi::grandpa::Call::report_equivocation(report) => {
|
||||
RuntimeCall::Grandpa(grandpa::Call::report_equivocation {
|
||||
// TODO: Find a better way to go from Proof<[u8; 32]> to Proof<H256>
|
||||
equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice())
|
||||
.unwrap(),
|
||||
key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData),
|
||||
})
|
||||
}
|
||||
serai_abi::grandpa::Call::report_equivocation_unsigned(report) => {
|
||||
RuntimeCall::Grandpa(grandpa::Call::report_equivocation_unsigned {
|
||||
// TODO: Find a better way to go from Proof<[u8; 32]> to Proof<H256>
|
||||
equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice())
|
||||
.unwrap(),
|
||||
key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData),
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<Call> for RuntimeCall {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<Call, ()> {
|
||||
Ok(match self {
|
||||
RuntimeCall::Timestamp(timestamp::Call::set { now }) => {
|
||||
Call::Timestamp(serai_abi::timestamp::Call::set { now })
|
||||
}
|
||||
RuntimeCall::Coins(call) => Call::Coins(match call {
|
||||
coins::Call::transfer { to, balance } => {
|
||||
serai_abi::coins::Call::transfer { to: to.into(), balance }
|
||||
}
|
||||
coins::Call::burn { balance } => serai_abi::coins::Call::burn { balance },
|
||||
coins::Call::burn_with_instruction { instruction } => {
|
||||
serai_abi::coins::Call::burn_with_instruction { instruction }
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::LiquidityTokens(call) => Call::LiquidityTokens(match call {
|
||||
coins::Call::transfer { to, balance } => {
|
||||
serai_abi::coins::LiquidityTokensCall::transfer { to: to.into(), balance }
|
||||
}
|
||||
coins::Call::burn { balance } => serai_abi::coins::LiquidityTokensCall::burn { balance },
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::Dex(call) => Call::Dex(match call {
|
||||
dex::Call::add_liquidity {
|
||||
coin,
|
||||
coin_desired,
|
||||
sri_desired,
|
||||
coin_min,
|
||||
sri_min,
|
||||
mint_to,
|
||||
} => serai_abi::dex::Call::add_liquidity {
|
||||
coin,
|
||||
coin_desired,
|
||||
sri_desired,
|
||||
coin_min,
|
||||
sri_min,
|
||||
mint_to: mint_to.into(),
|
||||
},
|
||||
dex::Call::remove_liquidity {
|
||||
coin,
|
||||
lp_token_burn,
|
||||
coin_min_receive,
|
||||
sri_min_receive,
|
||||
withdraw_to,
|
||||
} => serai_abi::dex::Call::remove_liquidity {
|
||||
coin,
|
||||
lp_token_burn,
|
||||
coin_min_receive,
|
||||
sri_min_receive,
|
||||
withdraw_to: withdraw_to.into(),
|
||||
},
|
||||
dex::Call::swap_exact_tokens_for_tokens { path, amount_in, amount_out_min, send_to } => {
|
||||
serai_abi::dex::Call::swap_exact_tokens_for_tokens {
|
||||
path,
|
||||
amount_in,
|
||||
amount_out_min,
|
||||
send_to: send_to.into(),
|
||||
}
|
||||
}
|
||||
dex::Call::swap_tokens_for_exact_tokens { path, amount_out, amount_in_max, send_to } => {
|
||||
serai_abi::dex::Call::swap_tokens_for_exact_tokens {
|
||||
path,
|
||||
amount_out,
|
||||
amount_in_max,
|
||||
send_to: send_to.into(),
|
||||
}
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::ValidatorSets(call) => Call::ValidatorSets(match call {
|
||||
validator_sets::Call::set_keys { network, removed_participants, key_pair, signature } => {
|
||||
serai_abi::validator_sets::Call::set_keys {
|
||||
network,
|
||||
removed_participants: <_>::try_from(
|
||||
removed_participants.into_iter().map(SeraiAddress::from).collect::<Vec<_>>(),
|
||||
)
|
||||
.unwrap(),
|
||||
key_pair,
|
||||
signature,
|
||||
}
|
||||
}
|
||||
validator_sets::Call::report_slashes { network, slashes, signature } => {
|
||||
serai_abi::validator_sets::Call::report_slashes {
|
||||
network,
|
||||
slashes: <_>::try_from(
|
||||
slashes
|
||||
.into_iter()
|
||||
.map(|(addr, slash)| (SeraiAddress::from(addr), slash))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.unwrap(),
|
||||
signature,
|
||||
}
|
||||
}
|
||||
validator_sets::Call::allocate { network, amount } => {
|
||||
serai_abi::validator_sets::Call::allocate { network, amount }
|
||||
}
|
||||
validator_sets::Call::deallocate { network, amount } => {
|
||||
serai_abi::validator_sets::Call::deallocate { network, amount }
|
||||
}
|
||||
validator_sets::Call::claim_deallocation { network, session } => {
|
||||
serai_abi::validator_sets::Call::claim_deallocation { network, session }
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::InInstructions(call) => Call::InInstructions(match call {
|
||||
in_instructions::Call::execute_batch { batch } => {
|
||||
serai_abi::in_instructions::Call::execute_batch { batch }
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::Signals(call) => Call::Signals(match call {
|
||||
signals::Call::register_retirement_signal { in_favor_of } => {
|
||||
serai_abi::signals::Call::register_retirement_signal { in_favor_of }
|
||||
}
|
||||
signals::Call::revoke_retirement_signal { retirement_signal_id } => {
|
||||
serai_abi::signals::Call::revoke_retirement_signal { retirement_signal_id }
|
||||
}
|
||||
signals::Call::favor { signal_id, for_network } => {
|
||||
serai_abi::signals::Call::favor { signal_id, for_network }
|
||||
}
|
||||
signals::Call::revoke_favor { signal_id, for_network } => {
|
||||
serai_abi::signals::Call::revoke_favor { signal_id, for_network }
|
||||
}
|
||||
signals::Call::stand_against { signal_id, for_network } => {
|
||||
serai_abi::signals::Call::stand_against { signal_id, for_network }
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::Babe(call) => Call::Babe(match call {
|
||||
babe::Call::report_equivocation { equivocation_proof, key_owner_proof } => {
|
||||
serai_abi::babe::Call::report_equivocation(serai_abi::babe::ReportEquivocation {
|
||||
// TODO: Find a better way to go from Proof<H256> to Proof<[u8; 32]>
|
||||
equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(),
|
||||
key_owner_proof: key_owner_proof.0.into(),
|
||||
})
|
||||
}
|
||||
babe::Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } => {
|
||||
serai_abi::babe::Call::report_equivocation_unsigned(serai_abi::babe::ReportEquivocation {
|
||||
// TODO: Find a better way to go from Proof<H256> to Proof<[u8; 32]>
|
||||
equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(),
|
||||
key_owner_proof: key_owner_proof.0.into(),
|
||||
})
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
RuntimeCall::Grandpa(call) => Call::Grandpa(match call {
|
||||
grandpa::Call::report_equivocation { equivocation_proof, key_owner_proof } => {
|
||||
serai_abi::grandpa::Call::report_equivocation(serai_abi::grandpa::ReportEquivocation {
|
||||
// TODO: Find a better way to go from Proof<H256> to Proof<[u8; 32]>
|
||||
equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(),
|
||||
key_owner_proof: key_owner_proof.0.into(),
|
||||
})
|
||||
}
|
||||
grandpa::Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } => {
|
||||
serai_abi::grandpa::Call::report_equivocation_unsigned(
|
||||
serai_abi::grandpa::ReportEquivocation {
|
||||
// TODO: Find a better way to go from Proof<H256> to Proof<[u8; 32]>
|
||||
equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(),
|
||||
key_owner_proof: key_owner_proof.0.into(),
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => Err(())?,
|
||||
}),
|
||||
_ => Err(())?,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -64,6 +64,8 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
|||
use babe::AuthorityId as BabeId;
|
||||
use grandpa::AuthorityId as GrandpaId;
|
||||
|
||||
mod abi;
|
||||
|
||||
/// Nonce of a transaction in the chain, for a given account.
|
||||
pub type Nonce = u32;
|
||||
|
||||
|
@ -81,7 +83,7 @@ pub type SignedExtra = (
|
|||
transaction_payment::ChargeTransactionPayment<Runtime>,
|
||||
);
|
||||
|
||||
pub type Transaction = serai_primitives::Transaction<RuntimeCall, SignedExtra>;
|
||||
pub type Transaction = serai_abi::tx::Transaction<RuntimeCall, SignedExtra>;
|
||||
pub type Block = generic::Block<Header, Transaction>;
|
||||
pub type BlockId = generic::BlockId<Block>;
|
||||
|
||||
|
@ -161,35 +163,9 @@ parameter_types! {
|
|||
pub struct CallFilter;
|
||||
impl Contains<RuntimeCall> for CallFilter {
|
||||
fn contains(call: &RuntimeCall) -> bool {
|
||||
match call {
|
||||
RuntimeCall::Timestamp(call) => match call {
|
||||
timestamp::Call::set { .. } => true,
|
||||
timestamp::Call::__Ignore(_, _) => false,
|
||||
},
|
||||
|
||||
// All of these pallets are our own, and all of their written calls are intended to be called
|
||||
RuntimeCall::Coins(call) => !matches!(call, coins::Call::__Ignore(_, _)),
|
||||
RuntimeCall::LiquidityTokens(call) => match call {
|
||||
coins::Call::transfer { .. } | coins::Call::burn { .. } => true,
|
||||
coins::Call::burn_with_instruction { .. } | coins::Call::__Ignore(_, _) => false,
|
||||
},
|
||||
RuntimeCall::Dex(call) => !matches!(call, dex::Call::__Ignore(_, _)),
|
||||
RuntimeCall::ValidatorSets(call) => !matches!(call, validator_sets::Call::__Ignore(_, _)),
|
||||
RuntimeCall::InInstructions(call) => !matches!(call, in_instructions::Call::__Ignore(_, _)),
|
||||
RuntimeCall::Signals(call) => !matches!(call, signals::Call::__Ignore(_, _)),
|
||||
|
||||
RuntimeCall::Babe(call) => match call {
|
||||
babe::Call::report_equivocation { .. } |
|
||||
babe::Call::report_equivocation_unsigned { .. } => true,
|
||||
babe::Call::plan_config_change { .. } | babe::Call::__Ignore(_, _) => false,
|
||||
},
|
||||
|
||||
RuntimeCall::Grandpa(call) => match call {
|
||||
grandpa::Call::report_equivocation { .. } |
|
||||
grandpa::Call::report_equivocation_unsigned { .. } => true,
|
||||
grandpa::Call::note_stalled { .. } | grandpa::Call::__Ignore(_, _) => false,
|
||||
},
|
||||
}
|
||||
// If the call is defined in our ABI, it's allowed
|
||||
let call: Result<serai_abi::Call, ()> = call.clone().try_into();
|
||||
call.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -873,7 +873,7 @@ pub mod pallet {
|
|||
pub fn set_keys(
|
||||
origin: OriginFor<T>,
|
||||
network: NetworkId,
|
||||
removed_participants: Vec<Public>,
|
||||
removed_participants: BoundedVec<Public, ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>,
|
||||
key_pair: KeyPair,
|
||||
signature: Signature,
|
||||
) -> DispatchResult {
|
||||
|
|
Loading…
Reference in a new issue