Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ cargo-timing*
/examples/parachain-example/target
/examples/parachain-example/metadata/target
.vscode
.claude
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ darling = "0.20.10"
derive-where = "1.2.7"
either = { version = "1.13.0", default-features = false }
finito = { version = "0.1.0", default-features = false }
frame-decode = { version = "0.16.1", default-features = false }
frame-decode = { version = "0.17.0", default-features = false }
frame-metadata = { version = "23.0.0", default-features = false }
futures = { version = "0.3.31", default-features = false, features = ["std"] }
getrandom = { version = "0.2", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Subxt is a library for interacting with chains in the [Polkadot](https://github.
- Do all of the above via a safe, statically typed interface or via a flexible dynamic interface.
- Do most of the above via a built-in light client to interact with chains trustlessly.
- Compile to WASM and run [entirely in the browser](./examples/wasm-example), or be [called via FFI](./examples/ffi-example) in many other languages.
- Be used entirely offline to provide a subset of the available functionality.

## Usage

Expand Down
2 changes: 1 addition & 1 deletion codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ fn default_substitutes(crate_path: &syn::Path) -> TypeSubstitutes {
),
(
parse_quote!(fp_account::AccountId20),
parse_quote!(#crate_path::utils::AccountId20),
parse_quote!(#crate_path::utils::eth::AccountId20),
),
(
parse_quote!(sp_runtime::multiaddress::MultiAddress),
Expand Down
8 changes: 4 additions & 4 deletions examples/ffi-example/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions examples/parachain-example/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions examples/wasm-example/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 4 additions & 7 deletions examples/wasm-example/src/routes/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use subxt::{client::OnlineClientAtBlockImpl, OnlineClient, OnlineClientAtBlock,

use subxt::config::DefaultExtrinsicParamsBuilder;
use subxt::ext::codec::{Decode, Encode};
use subxt::tx::Payload as _;
use subxt::tx::SubmittableTransaction;
use subxt::utils::{AccountId32, MultiSignature};

Expand All @@ -26,10 +25,7 @@ impl SigningExamplesComponent {
fn set_message(&mut self, message: String) {
let remark_call = polkadot::tx().system().remark(message.as_bytes().to_vec());
let online_client_at_block = self.online_client.as_ref().unwrap();
let remark_call_bytes = remark_call
.encode_call_data(online_client_at_block.metadata_ref())
.unwrap();
self.remark_call_bytes = remark_call_bytes;
self.remark_call_bytes = online_client_at_block.tx().call_data(&remark_call).unwrap();
self.message = message;
}
}
Expand Down Expand Up @@ -182,8 +178,9 @@ impl Component for SigningExamplesComponent {
};

// Apply the signature
let signed_extrinsic =
signable.sign_with_account_and_signature(&account_id, &multi_signature);
let Ok(signed_extrinsic) = signable.sign_with_account_and_signature(&account_id, &multi_signature) else {
return Message::Error(anyhow!("could not sign the extrinsic"));
};

// check the TX validity (to debug in the js console if the extrinsic would work)
let dry_res = signed_extrinsic.validate().await;
Expand Down
58 changes: 53 additions & 5 deletions metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use alloc::vec::Vec;
use frame_decode::constants::{ConstantEntry, ConstantInfo, ConstantInfoError};
use frame_decode::custom_values::{CustomValue, CustomValueInfo, CustomValueInfoError};
use frame_decode::extrinsics::{
ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
ExtrinsicSignatureInfo,
ExtrinsicCallInfo, ExtrinsicCallInfoArg, ExtrinsicExtensionInfo, ExtrinsicExtensionInfoArg,
ExtrinsicInfoError, ExtrinsicSignatureInfo,
};
use frame_decode::runtime_apis::{
RuntimeApiEntry, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput,
Expand Down Expand Up @@ -99,7 +99,7 @@ pub struct Metadata {
impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
type TypeId = u32;

fn extrinsic_call_info(
fn extrinsic_call_info_by_index(
&self,
pallet_index: u8,
call_index: u8,
Expand All @@ -119,12 +119,49 @@ impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
})?;

Ok(ExtrinsicCallInfo {
call_index,
pallet_index,
pallet_name: Cow::Borrowed(pallet.name()),
call_name: Cow::Borrowed(&call.name),
args: call
.fields
.iter()
.map(|f| ExtrinsicInfoArg {
.map(|f| ExtrinsicCallInfoArg {
name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
id: f.ty.id,
})
.collect(),
})
}

fn extrinsic_call_info_by_name(
&self,
pallet_name: &str,
call_name: &str,
) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
let pallet = self.pallet_by_name(pallet_name).ok_or({
ExtrinsicInfoError::PalletNotFoundByName {
name: Cow::Owned(pallet_name.to_string()),
}
})?;

let call = pallet.call_variant_by_name(call_name).ok_or_else(|| {
ExtrinsicInfoError::CallNotFoundByName {
pallet_index: pallet.call_index(),
pallet_name: Cow::Borrowed(pallet.name()),
call_name: Cow::Owned(call_name.to_string()),
}
})?;

Ok(ExtrinsicCallInfo {
call_index: call.index,
pallet_index: pallet.call_index(),
pallet_name: Cow::Borrowed(pallet.name()),
call_name: Cow::Borrowed(&call.name),
args: call
.fields
.iter()
.map(|f| ExtrinsicCallInfoArg {
name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
id: f.ty.id,
})
Expand All @@ -141,6 +178,16 @@ impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
})
}

fn extrinsic_extension_version_info(
&self,
) -> Result<impl Iterator<Item = u8>, ExtrinsicInfoError<'_>> {
Ok(self
.extrinsic
.transaction_extensions_by_version
.keys()
.copied())
}

fn extrinsic_extension_info(
&self,
extension_version: Option<u8>,
Expand All @@ -157,9 +204,10 @@ impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
.extrinsic()
.transaction_extensions_by_version(extension_version)
.ok_or(ExtrinsicInfoError::ExtrinsicExtensionVersionNotFound { extension_version })?
.map(|f| ExtrinsicInfoArg {
.map(|f| ExtrinsicExtensionInfoArg {
name: Cow::Borrowed(f.identifier()),
id: f.extra_ty(),
implicit_id: f.additional_ty(),
})
.collect();

Expand Down
24 changes: 18 additions & 6 deletions signer/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,20 @@ mod subxt_compat {
use super::*;
use subxt::config::Config;
use subxt::transactions::Signer as SignerT;
use subxt::utils::AccountId20;
use subxt::utils::MultiAddress;
use subxt::utils::eth::AccountId20;

impl From<Signature> for subxt::utils::eth::Signature {
fn from(value: Signature) -> Self {
subxt::utils::eth::Signature(value.0)
}
}

impl From<subxt::utils::eth::Signature> for Signature {
fn from(value: subxt::utils::eth::Signature) -> Self {
Signature(value.0)
}
}

impl<T: Config> SignerT<T> for Keypair
where
Expand Down Expand Up @@ -367,7 +379,7 @@ mod test {
use secp256k1::Secp256k1;
use subxt::config::{Config, HashFor, substrate};
use subxt::transactions::Signer as SignerT;
use subxt::utils::AccountId20;
use subxt::utils::eth::AccountId20;

use super::*;

Expand All @@ -377,10 +389,10 @@ mod test {
impl Config for StubEthRuntimeConfig {
type AccountId = AccountId20;
type Address = AccountId20;
type Signature = Signature;
type Signature = subxt::utils::eth::Signature;
type Hasher = substrate::BlakeTwo256;
type Header = substrate::SubstrateHeader<HashFor<Self>>;
type ExtrinsicParams = substrate::SubstrateExtrinsicParams<Self>;
type TransactionExtensions = substrate::SubstrateExtrinsicParams<Self>;
type AssetId = u32;
}

Expand Down Expand Up @@ -439,7 +451,7 @@ mod test {
let msg_as_bytes = msg.as_bytes();

assert_eq!(SubxtSigner::account_id(&keypair), keypair.public_key().to_account_id());
assert_eq!(SubxtSigner::sign(&keypair, msg_as_bytes), keypair.sign(msg_as_bytes));
assert_eq!(SubxtSigner::sign(&keypair, msg_as_bytes), keypair.sign(msg_as_bytes).into());
}

#[test]
Expand All @@ -459,7 +471,7 @@ mod test {

#[test]
fn check_signing_and_verifying_matches(keypair in keypair(), msg in ".*") {
let sig = SubxtSigner::sign(&keypair, msg.as_bytes());
let sig = SubxtSigner::sign(&keypair, msg.as_bytes()).into();

assert!(verify(
&sig,
Expand Down
5 changes: 3 additions & 2 deletions subxt/examples/config_assethub.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Configuring Subxt to talk to AssetHub.
use subxt::Error;
use subxt::config::{
Config, DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder, PolkadotConfig, SubstrateConfig,
Config, DefaultExtrinsicParamsBuilder, DefaultTransactionExtensions, PolkadotConfig,
SubstrateConfig,
};
use subxt_signer::sr25519::dev;

Expand Down Expand Up @@ -34,7 +35,7 @@ impl Config for AssetHubConfig {
type Signature = <SubstrateConfig as Config>::Signature;
type Hasher = <SubstrateConfig as Config>::Hasher;
type Header = <SubstrateConfig as Config>::Header;
type ExtrinsicParams = DefaultExtrinsicParams<AssetHubConfig>;
type TransactionExtensions = DefaultTransactionExtensions<AssetHubConfig>;

// Forward these methods to the default SubstrateConfig:
fn genesis_hash(&self) -> Option<subxt::config::HashFor<Self>> {
Expand Down
13 changes: 7 additions & 6 deletions subxt/examples/config_eth.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
//! Configuring Subxt to talk to AssetHub.
use subxt::Error;
use subxt::config::{Config, DefaultExtrinsicParams, SubstrateConfig};
use subxt::config::{Config, DefaultTransactionExtensions, SubstrateConfig};

/// Our EthConfig wraps SubstrateConfig and configures the
/// account ID / address / signature to be based on 20 byte IDs.
#[derive(Debug, Clone, Default)]
pub struct EthConfig(SubstrateConfig);

impl Config for EthConfig {
// AssetHub, like Polkadot, has no account index on its address type:
type Address = subxt::utils::AccountId20;
type AccountId = subxt::utils::AccountId20;
type Signature = subxt_signer::eth::Signature;
// Eth based chains use 20 byte account IDs
// and ecdsa based signing:
type Address = subxt::utils::eth::AccountId20;
type AccountId = subxt::utils::eth::AccountId20;
type Signature = subxt::utils::eth::Signature;

// Just copy the default SubstrateConfig for these:
type AssetId = <SubstrateConfig as Config>::AssetId;
type Hasher = <SubstrateConfig as Config>::Hasher;
type Header = <SubstrateConfig as Config>::Header;
type ExtrinsicParams = DefaultExtrinsicParams<EthConfig>;
type TransactionExtensions = DefaultTransactionExtensions<EthConfig>;

// Forward these methods to the default SubstrateConfig:
fn genesis_hash(&self) -> Option<subxt::config::HashFor<Self>> {
Expand Down
7 changes: 6 additions & 1 deletion subxt/examples/light_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let block = block?;

// Print some details about the blocks we fetch via the light client.
println!("Chain {:?} hash={:?}", chain, block.hash());
println!(
"Chain {:?} height={:?} hash={:?}",
chain,
block.number(),
block.hash()
);
let at_block = block.at().await?;
let extrinsics = at_block.extrinsics().fetch().await?;
for ext in extrinsics.iter() {
Expand Down
Loading
Loading