Replace substrate/client's use of Payload with usage of RuntimeCall

Gains explicit typing.
This commit is contained in:
Luke Parker 2023-11-22 11:23:00 -05:00
parent fcfdadc791
commit 08e6669403
No known key found for this signature in database
9 changed files with 93 additions and 105 deletions

View file

@ -5,9 +5,7 @@ use serai_runtime::{
pub use coins::primitives; pub use coins::primitives;
use primitives::OutInstructionWithBalance; use primitives::OutInstructionWithBalance;
use subxt::tx::Payload; use crate::{TemporalSerai, SeraiError, scale_value};
use crate::{TemporalSerai, SeraiError, Composite, scale_value, scale_composite};
const PALLET: &str = "Coins"; const PALLET: &str = "Coins";
@ -56,23 +54,22 @@ impl<'a> SeraiCoins<'a> {
)) ))
} }
pub fn transfer(to: SeraiAddress, balance: Balance) -> Payload<Composite<()>> { pub fn transfer(to: SeraiAddress, balance: Balance) -> serai_runtime::RuntimeCall {
Payload::new( serai_runtime::RuntimeCall::Coins(serai_runtime::coins::Call::<Runtime>::transfer {
PALLET, to: to.into(),
"transfer", balance,
scale_composite(serai_runtime::coins::Call::<Runtime>::transfer { to: to.into(), balance }), })
)
} }
pub fn burn(balance: Balance) -> Payload<Composite<()>> { pub fn burn(balance: Balance) -> serai_runtime::RuntimeCall {
Payload::new(PALLET, "burn", scale_composite(coins::Call::<Runtime>::burn { balance })) serai_runtime::RuntimeCall::Coins(serai_runtime::coins::Call::<Runtime>::burn { balance })
} }
pub fn burn_with_instruction(instruction: OutInstructionWithBalance) -> Payload<Composite<()>> { pub fn burn_with_instruction(
Payload::new( instruction: OutInstructionWithBalance,
PALLET, ) -> serai_runtime::RuntimeCall {
"burn_with_instruction", serai_runtime::RuntimeCall::Coins(
scale_composite(coins::Call::<Runtime>::burn_with_instruction { instruction }), serai_runtime::coins::Call::<Runtime>::burn_with_instruction { instruction },
) )
} }
} }

View file

@ -4,11 +4,7 @@ use serai_runtime::{
dex, Dex, Runtime, dex, Dex, Runtime,
}; };
use subxt::tx::Payload; use crate::{SeraiError, TemporalSerai};
use crate::{SeraiError, Composite, TemporalSerai, scale_composite};
const PALLET: &str = "Dex";
pub type DexEvent = dex::Event<Runtime>; pub type DexEvent = dex::Event<Runtime>;
@ -26,19 +22,15 @@ impl<'a> SeraiDex<'a> {
min_coin_amount: Amount, min_coin_amount: Amount,
min_sri_amount: Amount, min_sri_amount: Amount,
address: SeraiAddress, address: SeraiAddress,
) -> Payload<Composite<()>> { ) -> serai_runtime::RuntimeCall {
Payload::new( serai_runtime::RuntimeCall::Dex(dex::Call::<Runtime>::add_liquidity {
PALLET, coin,
"add_liquidity", coin_desired: coin_amount.0,
scale_composite(dex::Call::<Runtime>::add_liquidity { sri_desired: sri_amount.0,
coin, coin_min: min_coin_amount.0,
coin_desired: coin_amount.0, sri_min: min_sri_amount.0,
sri_desired: sri_amount.0, mint_to: address.into(),
coin_min: min_coin_amount.0, })
sri_min: min_sri_amount.0,
mint_to: address.into(),
}),
)
} }
pub fn swap( pub fn swap(
@ -47,7 +39,7 @@ impl<'a> SeraiDex<'a> {
amount_in: Amount, amount_in: Amount,
amount_out_min: Amount, amount_out_min: Amount,
address: SeraiAddress, address: SeraiAddress,
) -> Payload<Composite<()>> { ) -> serai_runtime::RuntimeCall {
let path = if to_coin.is_native() { let path = if to_coin.is_native() {
BoundedVec::try_from(vec![from_coin, Coin::Serai]).unwrap() BoundedVec::try_from(vec![from_coin, Coin::Serai]).unwrap()
} else if from_coin.is_native() { } else if from_coin.is_native() {
@ -56,15 +48,11 @@ impl<'a> SeraiDex<'a> {
BoundedVec::try_from(vec![from_coin, Coin::Serai, to_coin]).unwrap() BoundedVec::try_from(vec![from_coin, Coin::Serai, to_coin]).unwrap()
}; };
Payload::new( serai_runtime::RuntimeCall::Dex(dex::Call::<Runtime>::swap_exact_tokens_for_tokens {
PALLET, path,
"swap_exact_tokens_for_tokens", amount_in: amount_in.0,
scale_composite(dex::Call::<Runtime>::swap_exact_tokens_for_tokens { amount_out_min: amount_out_min.0,
path, send_to: address.into(),
amount_in: amount_in.0, })
amount_out_min: amount_out_min.0,
send_to: address.into(),
}),
)
} }
} }

View file

@ -2,8 +2,6 @@ use serai_runtime::{in_instructions, InInstructions, Runtime};
pub use in_instructions::primitives; pub use in_instructions::primitives;
use primitives::SignedBatch; use primitives::SignedBatch;
use subxt::utils::Encoded;
use crate::{ use crate::{
primitives::{BlockHash, NetworkId}, primitives::{BlockHash, NetworkId},
SeraiError, Serai, TemporalSerai, scale_value, SeraiError, Serai, TemporalSerai, scale_value,
@ -41,7 +39,7 @@ impl<'a> SeraiInInstructions<'a> {
.await .await
} }
pub fn execute_batch(batch: SignedBatch) -> Encoded { pub fn execute_batch(batch: SignedBatch) -> Vec<u8> {
Serai::unsigned::<InInstructions, _>(&in_instructions::Call::<Runtime>::execute_batch { batch }) Serai::unsigned::<InInstructions, _>(&in_instructions::Call::<Runtime>::execute_batch { batch })
} }
} }

View file

@ -4,7 +4,7 @@ use futures::stream::{Stream, StreamExt};
use scale::{Encode, Decode, Compact}; use scale::{Encode, Decode, Compact};
mod scale_value; mod scale_value;
pub(crate) use scale_value::{Value, Composite, scale_value, scale_composite}; pub(crate) use scale_value::{Value, scale_value};
pub use sp_core::{ pub use sp_core::{
Pair as PairTrait, Pair as PairTrait,
@ -14,13 +14,12 @@ pub use sp_core::{
pub use subxt; pub use subxt;
use subxt::{ use subxt::{
error::Error as SubxtError, error::Error as SubxtError,
utils::Encoded,
config::{ config::{
Header as HeaderTrait, Header as HeaderTrait,
substrate::{BlakeTwo256, SubstrateHeader}, substrate::{BlakeTwo256, SubstrateHeader},
extrinsic_params::{BaseExtrinsicParams, BaseExtrinsicParamsBuilder}, extrinsic_params::BaseExtrinsicParams,
}, },
tx::{Signer, Payload, TxClient}, tx::Signer,
rpc::types::{ChainBlock, ChainBlockExtrinsic}, rpc::types::{ChainBlock, ChainBlockExtrinsic},
Config as SubxtConfig, OnlineClient, Config as SubxtConfig, OnlineClient,
}; };
@ -149,7 +148,7 @@ impl Serai {
Ok(Serai(OnlineClient::<SeraiConfig>::from_url(url).await.map_err(SeraiError::RpcError)?)) Ok(Serai(OnlineClient::<SeraiConfig>::from_url(url).await.map_err(SeraiError::RpcError)?))
} }
fn unsigned<P: 'static, C: Encode>(call: &C) -> Encoded { fn unsigned<P: 'static, C: Encode>(call: &C) -> Vec<u8> {
// TODO: Should Serai purge the old transaction code AND set this to 0/1? // TODO: Should Serai purge the old transaction code AND set this to 0/1?
const TRANSACTION_VERSION: u8 = 4; const TRANSACTION_VERSION: u8 = 4;
@ -162,30 +161,54 @@ impl Serai {
bytes.extend(call.encode()); bytes.extend(call.encode());
// Prefix the length // Prefix the length
let mut complete_bytes = scale::Compact(u32::try_from(bytes.len()).unwrap()).encode(); let mut complete_bytes = Compact(u32::try_from(bytes.len()).unwrap()).encode();
complete_bytes.extend(bytes); complete_bytes.extend(bytes);
Encoded(complete_bytes) complete_bytes
} }
pub fn sign<S: Send + Sync + Signer<SeraiConfig>>( pub fn sign<S: Send + Sync + Signer<SeraiConfig>>(
&self, &self,
signer: &S, signer: &S,
payload: &Payload<Composite<()>>, call: &serai_runtime::RuntimeCall,
nonce: u32, nonce: u32,
params: BaseExtrinsicParamsBuilder<SeraiConfig, Tip>, tip: Tip,
) -> Result<Encoded, SeraiError> { ) -> Vec<u8> {
TxClient::new(self.0.offline()) const SPEC_VERSION: u32 = 100;
.create_signed_with_nonce(payload, signer, nonce, params) const IMPL_VERSION: u32 = 1;
.map(|tx| Encoded(tx.into_encoded())) const TRANSACTION_VERSION: u8 = 4;
// TODO: Don't have this potentially return an error (requires modifying the Payload type)
.map_err(|_| SeraiError::InvalidRuntime) let era = subxt::config::substrate::Era::Immortal;
let extra = (era, Compact(nonce), tip);
let genesis = self.0.genesis_hash();
let mortality_checkpoint = genesis;
let mut signature_payload =
(call, extra, SPEC_VERSION, IMPL_VERSION, genesis, mortality_checkpoint).encode();
if signature_payload.len() > 256 {
use subxt::config::Hasher;
signature_payload = BlakeTwo256::hash(&signature_payload).0.to_vec();
}
let signature = signer.sign(&signature_payload);
let signed = 1 << 7;
let extrinsic =
(signed + TRANSACTION_VERSION, signer.address(), signature, extra, call).encode();
let mut res = Compact(u32::try_from(extrinsic.len()).unwrap()).encode();
res.extend(&extrinsic);
res
} }
pub async fn publish(&self, tx: &Encoded) -> Result<(), SeraiError> { pub async fn publish(&self, tx: &[u8]) -> Result<(), SeraiError> {
// Drop the hash, which is the hash of the raw TX, as TXs are allowed to share hashes and this self
// hash is practically useless/unsafe .0
// If we are to return something, it should be block included in and position within block .rpc()
self.0.rpc().submit_extrinsic(tx).await.map(|_| ()).map_err(SeraiError::RpcError) .deref()
.request::<[u8; 32]>("author_submitExtrinsic", subxt::rpc::rpc_params![tx])
.await
// Drop the hash, which is the hash of the raw extrinsic, as extrinsics are allowed to share
// hashes and this hash is accordingly useless/unsafe
// If we are to return something, it should be block included in and position within block
.map(|_| ())
.map_err(SeraiError::RpcError)
} }
pub async fn latest_block_hash(&self) -> Result<[u8; 32], SeraiError> { pub async fn latest_block_hash(&self) -> Result<[u8; 32], SeraiError> {

View file

@ -2,8 +2,8 @@ use ::scale::Encode;
use scale_info::{MetaType, TypeInfo, Registry, PortableRegistry}; use scale_info::{MetaType, TypeInfo, Registry, PortableRegistry};
use subxt::ext::scale_value; use subxt::ext::scale_value;
pub(crate) use scale_value::{Composite, Value}; pub(crate) use scale_value::Value;
use scale_value::{ValueDef, scale}; use scale_value::scale;
pub(crate) fn scale_value<V: 'static + Encode + TypeInfo>(value: V) -> Value { pub(crate) fn scale_value<V: 'static + Encode + TypeInfo>(value: V) -> Value {
let mut registry = Registry::new(); let mut registry = Registry::new();
@ -11,11 +11,3 @@ pub(crate) fn scale_value<V: 'static + Encode + TypeInfo>(value: V) -> Value {
let registry = PortableRegistry::from(registry); let registry = PortableRegistry::from(registry);
scale::decode_as_type(&mut value.encode().as_ref(), id, &registry).unwrap().remove_context() scale::decode_as_type(&mut value.encode().as_ref(), id, &registry).unwrap().remove_context()
} }
pub(crate) fn scale_composite<V: 'static + Encode + TypeInfo>(value: V) -> Composite<()> {
match scale_value(value).value {
ValueDef::Composite(composite) => composite,
ValueDef::Variant(variant) => variant.values,
_ => panic!("not composite"),
}
}

View file

@ -4,8 +4,6 @@ use serai_runtime::{primitives::Amount, validator_sets, ValidatorSets, Runtime};
pub use validator_sets::primitives; pub use validator_sets::primitives;
use primitives::{Session, ValidatorSet, KeyPair}; use primitives::{Session, ValidatorSet, KeyPair};
use subxt::utils::Encoded;
use crate::{primitives::NetworkId, Serai, TemporalSerai, SeraiError, scale_value}; use crate::{primitives::NetworkId, Serai, TemporalSerai, SeraiError, scale_value};
const PALLET: &str = "ValidatorSets"; const PALLET: &str = "ValidatorSets";
@ -82,7 +80,7 @@ impl<'a> SeraiValidatorSets<'a> {
self.0.storage(PALLET, "Keys", Some(vec![scale_value(set)])).await self.0.storage(PALLET, "Keys", Some(vec![scale_value(set)])).await
} }
pub fn set_keys(network: NetworkId, key_pair: KeyPair, signature: Signature) -> Encoded { pub fn set_keys(network: NetworkId, key_pair: KeyPair, signature: Signature) -> Vec<u8> {
Serai::unsigned::<ValidatorSets, _>(&validator_sets::Call::<Runtime>::set_keys { Serai::unsigned::<ValidatorSets, _>(&validator_sets::Call::<Runtime>::set_keys {
network, network,
key_pair, key_pair,

View file

@ -11,7 +11,6 @@ use serai_runtime::coins::primitives::OutInstructionWithBalance;
use sp_core::Pair; use sp_core::Pair;
use serai_client::{ use serai_client::{
subxt::config::extrinsic_params::BaseExtrinsicParamsBuilder,
primitives::{ primitives::{
Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, Data, ExternalAddress, Amount, NetworkId, Coin, Balance, BlockHash, SeraiAddress, Data, ExternalAddress,
insecure_pair_from_name, insecure_pair_from_name,
@ -95,9 +94,8 @@ serai_test!(
&PairSigner::new(pair), &PairSigner::new(pair),
&SeraiCoins::burn_with_instruction(instruction.clone()), &SeraiCoins::burn_with_instruction(instruction.clone()),
0, 0,
BaseExtrinsicParamsBuilder::new(), Default::default(),
) )
.unwrap(),
) )
.await; .await;

View file

@ -3,8 +3,6 @@ use serai_runtime::primitives::{Coin, Amount};
use serai_client::{Serai, SeraiDex, PairSigner}; use serai_client::{Serai, SeraiDex, PairSigner};
use sp_core::{sr25519::Pair, Pair as PairTrait}; use sp_core::{sr25519::Pair, Pair as PairTrait};
use subxt::config::extrinsic_params::BaseExtrinsicParamsBuilder;
use crate::common::tx::publish_tx; use crate::common::tx::publish_tx;
#[allow(dead_code)] #[allow(dead_code)]
@ -18,14 +16,12 @@ pub async fn add_liquidity(
) -> [u8; 32] { ) -> [u8; 32] {
let address = pair.public(); let address = pair.public();
let tx = serai let tx = serai.sign(
.sign( &PairSigner::new(pair),
&PairSigner::new(pair), &SeraiDex::add_liquidity(coin, coin_amount, sri_amount, Amount(1), Amount(1), address.into()),
&SeraiDex::add_liquidity(coin, coin_amount, sri_amount, Amount(1), Amount(1), address.into()), nonce,
nonce, Default::default(),
BaseExtrinsicParamsBuilder::new(), );
)
.unwrap();
publish_tx(serai, &tx).await publish_tx(serai, &tx).await
} }
@ -42,14 +38,12 @@ pub async fn swap(
) -> [u8; 32] { ) -> [u8; 32] {
let address = pair.public(); let address = pair.public();
let tx = serai let tx = serai.sign(
.sign( &PairSigner::new(pair),
&PairSigner::new(pair), &SeraiDex::swap(from_coin, to_coin, amount_in, amount_out_min, address.into()),
&SeraiDex::swap(from_coin, to_coin, amount_in, amount_out_min, address.into()), nonce,
nonce, Default::default(),
BaseExtrinsicParamsBuilder::new(), );
)
.unwrap();
publish_tx(serai, &tx).await publish_tx(serai, &tx).await
} }

View file

@ -2,10 +2,10 @@ use core::time::Duration;
use tokio::time::sleep; use tokio::time::sleep;
use serai_client::{subxt::utils::Encoded, Serai}; use serai_client::Serai;
#[allow(dead_code)] #[allow(dead_code)]
pub async fn publish_tx(serai: &Serai, tx: &Encoded) -> [u8; 32] { pub async fn publish_tx(serai: &Serai, tx: &[u8]) -> [u8; 32] {
let mut latest = let mut latest =
serai.block(serai.latest_block_hash().await.unwrap()).await.unwrap().unwrap().number(); serai.block(serai.latest_block_hash().await.unwrap()).await.unwrap().unwrap().number();
@ -34,7 +34,7 @@ pub async fn publish_tx(serai: &Serai, tx: &Encoded) -> [u8; 32] {
}; };
for transaction in block.transactions() { for transaction in block.transactions() {
if transaction.0 == tx.0[2 ..] { if transaction.0 == tx[2 ..] {
return block.hash(); return block.hash();
} }
} }