Skip to content

Commit

Permalink
add more examples
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasad1 committed Oct 31, 2024
1 parent 68e0e7a commit 3189731
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 5 deletions.
208 changes: 208 additions & 0 deletions subxt/examples/substrate_compat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#![allow(missing_docs, unused)]

use codec::{Decode, Encode};
use polkadot_sdk::sp_core::{self, sr25519, Pair as PairT};
use polkadot_sdk::sp_runtime::{
self,
traits::{IdentifyAccount, Verify},
AccountId32 as SpAccountId32, MultiSignature as SpMultiSignature,
};
use subxt::config::PolkadotExtrinsicParams;
use subxt::{Config, OnlineClient};

#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
pub mod polkadot {}

pub enum PolkadotConfig {}

/// AccountId32 for substrate compatibility.
#[derive(
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
Encode,
Decode,
Debug,
scale_encode::EncodeAsType,
scale_decode::DecodeAsType,
scale_info::TypeInfo,
)]
pub struct AccountId32(subxt::config::substrate::AccountId32);

impl From<sp_runtime::AccountId32> for AccountId32 {
fn from(acc: sp_runtime::AccountId32) -> Self {
Self(subxt::config::substrate::AccountId32(acc.into()))
}
}

/// MultiAddress type for substrate compatibility.
#[derive(
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
Encode,
Decode,
Debug,
scale_encode::EncodeAsType,
scale_decode::DecodeAsType,
scale_info::TypeInfo,
)]
pub struct MultiAddress<AccountId, AccountIndex>(
subxt::config::substrate::MultiAddress<AccountId, AccountIndex>,
);

impl<AccountId, AccountIndex> From<AccountId> for MultiAddress<AccountId, AccountIndex> {
fn from(a: AccountId) -> Self {
Self(subxt::config::substrate::MultiAddress::Id(a))
}
}

/// MultiAddress type for substrate compatibility.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, scale_info::TypeInfo)]
pub struct MultiSignature(subxt::config::substrate::MultiSignature);

impl From<sp_runtime::MultiSignature> for MultiSignature {
fn from(value: sp_runtime::MultiSignature) -> Self {
let inner = match value {
sp_runtime::MultiSignature::Ed25519(s) => {
subxt::config::substrate::MultiSignature::Ed25519(s.0)
}
sp_runtime::MultiSignature::Sr25519(s) => {
subxt::config::substrate::MultiSignature::Sr25519(s.0)
}
sp_runtime::MultiSignature::Ecdsa(s) => {
subxt::config::substrate::MultiSignature::Ecdsa(s.0)
}
};
Self(inner)
}
}

impl From<sp_core::ed25519::Signature> for MultiSignature {
fn from(value: sp_core::ed25519::Signature) -> Self {
let sig: sp_runtime::MultiSignature = value.into();
sig.into()
}
}

impl From<sp_core::sr25519::Signature> for MultiSignature {
fn from(value: sp_core::sr25519::Signature) -> Self {
let sig: sp_runtime::MultiSignature = value.into();
sig.into()
}
}

impl From<sp_core::ecdsa::Signature> for MultiSignature {
fn from(value: sp_core::ecdsa::Signature) -> Self {
let sig: sp_runtime::MultiSignature = value.into();
sig.into()
}
}

impl subxt::Config for PolkadotConfig {
type Hash = <subxt::PolkadotConfig as Config>::Hash;
type AccountId = AccountId32;
type Address = MultiAddress<Self::AccountId, ()>;
type Signature = MultiSignature;
type Hasher = <subxt::PolkadotConfig as Config>::Hasher;
type Header = <subxt::PolkadotConfig as Config>::Header;
type ExtrinsicParams = PolkadotExtrinsicParams<Self>;
type AssetId = u32;
}

/// A [`Signer`] implementation that can be constructed from an [`sp_core::Pair`].
#[derive(Clone, Debug)]
pub struct PairSigner<T: Config, Pair> {
account_id: T::AccountId,
signer: Pair,
}

impl<T, Pair> PairSigner<T, Pair>
where
T: Config,
Pair: PairT,
// We go via an `sp_runtime::MultiSignature`. We can probably generalise this
// by implementing some of these traits on our built-in MultiSignature and then
// requiring them on all T::Signatures, to avoid any go-between.
<SpMultiSignature as Verify>::Signer: From<Pair::Public>,
T::AccountId: From<SpAccountId32>,
{
/// Creates a new [`Signer`] from an [`sp_core::Pair`].
pub fn new(signer: Pair) -> Self {
let account_id = <SpMultiSignature as Verify>::Signer::from(signer.public()).into_account();
Self {
account_id: account_id.into(),
signer,
}
}

/// Returns the [`sp_core::Pair`] implementation used to construct this.
pub fn signer(&self) -> &Pair {
&self.signer
}

/// Return the account ID.
pub fn account_id(&self) -> &T::AccountId {
&self.account_id
}
}

impl<T, Pair> subxt::tx::Signer<T> for PairSigner<T, Pair>
where
T: Config,
Pair: PairT,
Pair::Signature: Into<T::Signature>,
{
fn account_id(&self) -> T::AccountId {
self.account_id.clone()
}

fn address(&self) -> T::Address {
self.account_id.clone().into()
}

fn sign(&self, signer_payload: &[u8]) -> T::Signature {
self.signer.sign(signer_payload).into()
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();

// Create a new API client, configured to talk to Polkadot nodes.
let api = OnlineClient::<PolkadotConfig>::new().await?;

let signer: PairSigner<PolkadotConfig, _> = {
let acc = sr25519::Pair::from_string("//Alice", None)?;
PairSigner::new(acc)
};

let dest = subxt_signer::sr25519::dev::bob().public_key().into();

// Build a balance transfer extrinsic.
let balance_transfer_tx = polkadot::tx()
.balances()
.transfer_allow_death(dest, 100_000);

// Submit the balance transfer extrinsic from Alice, and wait for it to be successful
// and in a finalized block. We get back the extrinsic events if all is well.
let events = api
.tx()
.sign_and_submit_then_watch_default(&balance_transfer_tx, &signer)
.await?
.wait_for_finalized_success()
.await?;

// Find a Transfer event and print it.
let transfer_event = events.find_first::<polkadot::balances::events::Transfer>()?;
if let Some(event) = transfer_event {
println!("Balance transfer success: {event:?}");
}

Ok(())
}
20 changes: 15 additions & 5 deletions subxt/examples/substrate_compat_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,28 @@ mod pair_signer {
tx::Signer,
};

/// A [`Signer`] implementation for `polkadot_sdk::sp_core::sr25519::Pair`.
/// A [`Signer`] implementation for [`polkadot_sdk::sp_core::sr25519::Pair`].
#[derive(Clone)]
pub struct PairSigner {
account_id: <PolkadotConfig as Config>::AccountId,
signer: sr25519::Pair,
}

impl PairSigner {
/// Creates a new [`Signer`] from an [`sp_core::Pair`].
/// Creates a new [`Signer`] from an [`sp_core::sr25519::Pair`].
pub fn new(signer: sr25519::Pair) -> Self {
let account_id =
<SpMultiSignature as Verify>::Signer::from(signer.public()).into_account();
Self {
// Convert `sp_core::AccountId32` to `subxt::config::substrate::AccountId32`.
//
// This is necessary because we use `subxt::config::substrate::AccountId32` and no
// From/Into impls are provided between `sp_core::AccountId32` because `polkadot-sdk` isn't a direct
// dependency in subxt.
//
// This can also be done by provided a wrapper type around `subxt::config::substrate::AccountId32` to implement
// such conversions but that also most likely requires a custom `Config` with a separate `AccountId` type to work
// properly without additional hacks.
account_id: AccountId32(account_id.into()),
signer,
}
Expand Down Expand Up @@ -73,20 +81,22 @@ mod pair_signer {

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();

// Create a new API client, configured to talk to Polkadot nodes.
let api = OnlineClient::<PolkadotConfig>::new().await?;

let signer = {
let acc = sr25519::Pair::from_string("//Alice", None).unwrap();
let acc = sr25519::Pair::from_string("//Alice", None)?;
pair_signer::PairSigner::new(acc)
};

let alice = signer.account_id().clone().into();
let dest = subxt_signer::sr25519::dev::bob().public_key().into();

// Build a balance transfer extrinsic.
let balance_transfer_tx = polkadot::tx()
.balances()
.transfer_allow_death(alice, 10_000);
.transfer_allow_death(dest, 100_000);

// Submit the balance transfer extrinsic from Alice, and wait for it to be successful
// and in a finalized block. We get back the extrinsic events if all is well.
Expand Down

0 comments on commit 3189731

Please sign in to comment.