mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-23 03:59:22 +00:00
Replace substrate/client's use of Payload with usage of RuntimeCall
Gains explicit typing.
This commit is contained in:
parent
fcfdadc791
commit
08e6669403
9 changed files with 93 additions and 105 deletions
|
@ -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 },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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, ®istry).unwrap().remove_context()
|
scale::decode_as_type(&mut value.encode().as_ref(), id, ®istry).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"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue