mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +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:
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user