Skip to content
This repository was archived by the owner on Aug 15, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
d4c426a
[ci] Enable zombienet jobs in PRs (#2361)
alvicsam Nov 16, 2023
02e8061
westend: remove SessionKeys migration already applied on-chain (#2363)
acatangiu Nov 16, 2023
5e98803
implementers-guide: update github link (#2368)
Nov 16, 2023
4ac2db8
Fix Typo: `PalletXcmExtrinsicsBenchmark` (#2354)
joepetrowski Nov 16, 2023
596088a
add pallet nomination-pools versioned migration to kitchensink (#2167)
brunopgalvao Nov 17, 2023
b85c64a
fix typo (#2377)
cuteolaf Nov 17, 2023
20723ea
bump zombienet version `v1.3.80` (#2376)
pepoviola Nov 17, 2023
2e001de
[NPoS] Check if staker is exposed in paged exposure storage entries (…
Ank4n Nov 17, 2023
3ab2bc9
Beefy: small fixes (#2378)
serban300 Nov 17, 2023
5007e2d
crypto: `lazy_static` removed, light parser for address URI added (#2…
michalkucharczyk Nov 17, 2023
490fb66
[trivial] asset-hubs runtimes: fix incorrect doc-comments (#2384)
acatangiu Nov 17, 2023
079b14f
Do not panic if the `fdlimit` call to increase the file descriptor li…
nazar-pc Nov 17, 2023
0385902
Relax `force_default_xcm_version` for testnet system parachains (#2385)
bkontur Nov 17, 2023
9e34163
Make collator RPC mode non-experimental (#2381)
skunert Nov 17, 2023
82912ac
Fix migrations and add CI check for new system chains (#2336)
liamaharon Nov 17, 2023
1d1c371
Bump bandersnatch VRF revision (#2389)
davxy Nov 17, 2023
794ee98
Bump secp256k1 from 0.24.3 to 0.28.0 (#2357)
dependabot[bot] Nov 18, 2023
b585893
Preserve artifact cache unless stale (#1918)
eagr Nov 19, 2023
aa5705b
Pools: Add `MaxUnbonding` to metadata (#2397)
Nov 20, 2023
b35300c
Bump docker/build-push-action from 5.0.0 to 5.1.0 (#2404)
dependabot[bot] Nov 20, 2023
ede4a36
remove retry from backers on failed candidate validation (#2182)
jpserrat Nov 20, 2023
126f64a
bump zombienet version `v1.3.82` (#2396)
pepoviola Nov 21, 2023
2fd8c51
`chain-spec-builder`: cleanup (#2174)
michalkucharczyk Nov 21, 2023
0619049
Refactor `ValidationError` (#2406)
eagr Nov 21, 2023
40afc77
Add output positional arg to undying-collator cli (#2375)
pepoviola Nov 21, 2023
552be48
PVF worker: switch on seccomp networking restrictions (#2221)
mrcnski Nov 21, 2023
b25d29a
cumulus-consensus-common: block import: `delayed_best_block` flag add…
michalkucharczyk Nov 21, 2023
b3841b6
Different XCM builders, default one requires fee payment (#2253)
franciscoaguirre Nov 21, 2023
f5ad32e
added action to pass review bot on merge queue (#2414)
Bullrich Nov 21, 2023
50811d6
Update tick collator for async backing (#1497)
Sophia-Gold Nov 21, 2023
2183669
cumulus-test-service: block import fix (#2430)
michalkucharczyk Nov 21, 2023
7a32f4b
Deprecate `RewardDestination::Controller` (#2380)
Nov 22, 2023
a9ba1e5
Revert docker images tag naming to <prnum-shortsha> (#2434)
alvicsam Nov 22, 2023
98f9e2e
Fixes import path in benchmark macro (#2437)
gupnik Nov 22, 2023
408af9b
PVF: Fix unshare "no such file or directory" error (#2426)
mrcnski Nov 22, 2023
0d6dcb3
Make TypeInfo for SkipCheckIfFeeless transparent, too (#2449)
jsdw Nov 22, 2023
0956357
work with additional key values (#1757)
girazoki Nov 22, 2023
4987488
polkadot-node-subsystems: `ChainApiBackend` added + `polkadot-debug` …
michalkucharczyk Nov 22, 2023
ec18933
Remove `#[macro_use]` annotation from `mod service` in all nodes. (#2…
JoshOrndorff Nov 22, 2023
2d09e83
Add `on-chain-release-build` feature for Collectives Westend (#2463)
liamaharon Nov 23, 2023
12062f6
CI: Disable runtime upgrade spec name check on Westend Asset Hub and …
liamaharon Nov 23, 2023
21f1811
sp-api: Move macro related re-exports to `__private` (#2446)
bkchr Nov 23, 2023
19c05e8
Fix trait imports from sp-api (#2472)
andresilva Nov 23, 2023
c29b74d
Amend staking docs to account for state of controller deprecation (#2…
Nov 23, 2023
a00a767
Make publish CI consistant and bump to v0.3.0 (#2453)
Morganamilo Nov 24, 2023
4163152
pallet-xcm: ensure xcm outcome is always complete, revert effects oth…
xlc Nov 24, 2023
f086d54
pallet-staking: Converts all math operations to safe (#2435)
gpestana Nov 24, 2023
e3242d2
Adapt test worker to profile flag (#2450)
eagr Nov 24, 2023
471eafc
Disable any peer connections for parachain nodes in pov-recovery zom…
skunert Nov 24, 2023
7554f53
Remove dmp-queue pallet from Rococo Asset Hub and Bridge Hub (#2483)
liamaharon Nov 24, 2023
891628a
relay-chain-consensus: set a fork_choice (#2462)
michalkucharczyk Nov 24, 2023
803ea76
Improve `UnpinHandleInner` debug (#2485)
bkchr Nov 24, 2023
07ea6da
Derive `MaxEncodedLen` on `SlotDuration` (#2484)
nazar-pc Nov 24, 2023
90488ff
pallet-xcm: fix benchmarking (#2489)
acatangiu Nov 24, 2023
8af61d0
[NPoS] Use EraInfo to manipulate exposure in fast-unstake tests (#2459)
Ank4n Nov 24, 2023
d07186b
Remove `RuntimeApi` dependency on system parachain runtime code (#2455)
seadanda Nov 24, 2023
81638d4
Add missing workspace members (#2491)
ggwpez Nov 24, 2023
63f1210
bump zombienet version `v1.3.83` (#2492)
pepoviola Nov 24, 2023
5e27342
Do not pollute global base path with export genesis/wasm (#2487)
bkchr Nov 24, 2023
ffc64fd
Zombienet: add polkadot-debug image publish as needs for cumulus test…
pepoviola Nov 24, 2023
d5d15a1
polkadot-parachain: one chain-spec for all (#2457)
michalkucharczyk Nov 25, 2023
73ff1c3
Update documentation for SafeMode and TxPause Pallets (#2413)
wilwade Nov 25, 2023
cfa19c3
PVF: remove audit log access (#2461)
mrcnski Nov 25, 2023
4f8048b
New runtime `spec_version` format + backport of the bump to 1.4.0 (#2…
chevdor Nov 27, 2023
dc69dbb
Zombienet tests - disputes on finalized blocks (#2184)
Overkillus Nov 27, 2023
0317501
Decomissioned PR-Custom-Review (#2503)
Bullrich Nov 27, 2023
2610450
Build the standard library crates when building the runtimes (#2217)
koute Nov 27, 2023
4298bc6
asset-hub-westend-integration-tests: add more asset transfers tests (…
acatangiu Nov 27, 2023
fd1ed40
Remove the timestamp handler (#2506)
rcny Nov 27, 2023
838a534
Staking: `chill_other` takes stash instead of controller (#2501)
Nov 27, 2023
db29099
CI: Fix `build-and-attach-release-runtimes.yml` (#2471)
liamaharon Nov 28, 2023
2ac23d2
Fixes cumulus README instructions (#2442)
gpestana Nov 28, 2023
7506271
Pools: Add ability to configure commission claiming permissions (#2474)
Nov 28, 2023
0f7ffc6
Added NetworkId::PolkadotBulletin variant (#2517)
svyatonik Nov 28, 2023
58a1f9c
polkadot: disable block authoring backoff on production networks (#2510)
andresilva Nov 28, 2023
6dc3e6c
Set `frame_system::LastRuntimeUpgrade` after running `try-runtime` mi…
liamaharon Nov 28, 2023
6a417eb
Increase `cargo-check-each-crate-macos` timeout (#2519)
rcny Nov 28, 2023
cd8741c
Moves all test runtimes to use `derive_impl` (#2409)
gupnik Nov 28, 2023
dbd8d20
PVF: Add test instructions (#2058)
mrcnski Nov 28, 2023
f01781a
Remove `wasm-builder`'s README (#2525)
koute Nov 28, 2023
c5f211d
Remove `im-online` pallet from Rococo and Westend (#2265)
s0me0ne-unkn0wn Nov 28, 2023
b0b4451
polkadot: remove grandpa pause support (#2511)
andresilva Nov 28, 2023
ec3a61e
Remove pov-recovery race condition/Improve zombienet test (#2526)
skunert Nov 28, 2023
e71c484
Rework the event system of `sc-network` (#1370)
altonen Nov 28, 2023
aada961
[ci] Run gitspiegel trigger with merge conflicts (#2531)
alvicsam Nov 28, 2023
8201793
Remove long deprecated `AllPalletsWithoutSystemReversed` (#2509)
skunert Nov 28, 2023
a9aa2d1
Remove `dmp_queue` pallet from Westend SP runtimes (#2516)
liamaharon Nov 29, 2023
1d5d4a4
Enable parallel key scraping (#1985)
eagr Nov 29, 2023
39d6c95
substrate-node: `NativeElseWasmExecutor` is no longer used (#2521)
michalkucharczyk Nov 29, 2023
63ac247
Remove system parachains Polkadot and Kusama runtimes (#1737)
seadanda Nov 29, 2023
f2fe6a4
Improve `CodeExecutor` (#2358)
yjhmelody Nov 29, 2023
19f665f
add Rotko common good parachain nodes (#2533)
hitchhooker Nov 29, 2023
8f03570
Bump fs4 from 0.6.6 to 0.7.0 (#1844)
dependabot[bot] Nov 29, 2023
d3d301f
ParachainHost: No need to be generic over the block or hash type (#2537)
bkchr Nov 29, 2023
2858cbc
Adding LuckyFriday's Bootnodes per IBP Application (#2538)
paradox-tt Nov 29, 2023
08f29af
sp-api: Sprinkle some `automatically_derived` attributes
bkchr Nov 29, 2023
eb46b99
Disable trace-level logging from the `test-linux-stable-int` (#2546)
rcny Nov 29, 2023
ecdf343
chainHead: Backport error codes from spec (#2539)
lexnv Nov 29, 2023
c68ce6e
state-db: log_target usage fixed (#2547)
michalkucharczyk Nov 29, 2023
f69069b
Parachain Template: Prune `AuxStore` bound and corresponding crate de…
JoshOrndorff Nov 29, 2023
2135fa8
Contracts: use compiled rust tests (#2347)
pgherveou Nov 29, 2023
e41a0e7
upgraded review bot to 2.3.0 (#2549)
Bullrich Nov 30, 2023
180a6ad
Register metrics for the notification handles (#2562)
altonen Nov 30, 2023
eaf1bc5
Introduce Polkadot-Sdk `developer_hub` (#2102)
kianenigma Nov 30, 2023
64361ac
Withdraw Assets Before Checking Out in `OnReapIdentity` impl (#2552)
joepetrowski Nov 30, 2023
9a650c4
PoV Reclaim (Clawback) Node Side (#1462)
skunert Nov 30, 2023
c30ed6f
Add missing glossary to ref docs (#2572)
juangirini Nov 30, 2023
6742aba
Bump the known_good_semver group with 2 updates (#2570)
dependabot[bot] Nov 30, 2023
1f2ccae
Remove dependency on rand's SliceRandom shuffle implementation in gos…
rphmeier Nov 30, 2023
5213263
Add `recorded_keys` function to get recorded keys from the proof reco…
ParthDesai Dec 1, 2023
4a293bc
Enforce consistent and correct toml formatting (#2518)
liamaharon Dec 1, 2023
dfd7b15
Contracts: make benchmark dependencies optional in `std` feature (#2576)
ascjones Dec 1, 2023
7f0beaf
Bump proc-macro-crate from 1.3.1 to 2.0.0 (#2557)
dependabot[bot] Dec 1, 2023
095f4bd
Sassafras Consensus Pallet (#1577)
davxy Dec 1, 2023
87a73e7
Bump the known_good_semver group with 1 update (#2575)
dependabot[bot] Dec 1, 2023
5789d6a
sassafras: taplo happy (#2583)
michalkucharczyk Dec 1, 2023
ecfdb2b
Bandersnatch: ring-context generic over domain size (#2581)
davxy Dec 1, 2023
f5051c8
Removed instruction to call init.sh when buidling from source (#2580)
jonathanudd Dec 2, 2023
707dbcc
impl guide: update PVF host page; add diagrams (#2579)
mrcnski Dec 4, 2023
35c39c9
Fixes runtime type with doc parsing in derive_impl (#2594)
gupnik Dec 4, 2023
1266de3
Cleanup XCMP `QueueConfigData` (#2142)
serban300 Dec 4, 2023
ae4d24c
Merge branch 'master' into update-snowbridge
Dec 5, 2023
b03a1e7
fix tests
Dec 6, 2023
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
Prev Previous commit
Next Next commit
Different XCM builders, default one requires fee payment (paritytech#…
…2253)

Adding on top of the new builder pattern for creating XCM programs, I'm
adding some more APIs:

```rust
let paying_fees: Xcm<()> = Xcm::builder() // Only allow paying for fees
  .withdraw_asset() // First instruction has to load the holding register
  .buy_execution() // Second instruction has to be `buy_execution`
  .build();

let paying_fees_invalid: Xcm<()> = Xcm::builder()
  .withdraw_asset()
  .build(); // Invalid, need to pay for fees

let not_paying_fees: Xcm<()> = Xcm::builder_unpaid()
  .unpaid_execution() // Needed
  .withdraw_asset()
  .deposit_asset()
  .build();

let all_goes: Xcm<()> = Xcm::builder_unsafe() // You can do anything
  .withdraw_asset()
  .deposit_asset()
  .build();
```

The invalid bits are because the methods don't even exist on the types
that you'd want to call them on.

---------

Co-authored-by: command-bot <>
  • Loading branch information
franciscoaguirre authored Nov 21, 2023
commit b3841b6b71cd3707d80e90492059d1a2e3bd33a6
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions polkadot/xcm/procedural/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Inflector = "0.11.4"

[dev-dependencies]
trybuild = { version = "1.0.74", features = ["diff"] }
xcm = { package = "staging-xcm", path = ".." }
287 changes: 255 additions & 32 deletions polkadot/xcm/procedural/src/builder_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,83 @@
//! Derive macro for creating XCMs with a builder pattern

use inflector::Inflector;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::{
parse_macro_input, Data, DeriveInput, Error, Expr, ExprLit, Fields, Lit, Meta, MetaNameValue,
Data, DataEnum, DeriveInput, Error, Expr, ExprLit, Fields, Ident, Lit, Meta, MetaNameValue,
Result, Variant,
};

pub fn derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let builder_impl = match &input.data {
Data::Enum(data_enum) => generate_methods_for_enum(input.ident, data_enum),
_ =>
return Error::new_spanned(&input, "Expected the `Instruction` enum")
.to_compile_error()
.into(),
pub fn derive(input: DeriveInput) -> Result<TokenStream2> {
let data_enum = match &input.data {
Data::Enum(data_enum) => data_enum,
_ => return Err(Error::new_spanned(&input, "Expected the `Instruction` enum")),
};
let builder_raw_impl = generate_builder_raw_impl(&input.ident, data_enum);
let builder_impl = generate_builder_impl(&input.ident, data_enum)?;
let builder_unpaid_impl = generate_builder_unpaid_impl(&input.ident, data_enum)?;
let output = quote! {
pub struct XcmBuilder<Call>(Vec<Instruction<Call>>);
/// A trait for types that track state inside the XcmBuilder
pub trait XcmBuilderState {}

/// Access to all the instructions
pub enum AnythingGoes {}
/// You need to pay for execution
pub enum PaymentRequired {}
/// The holding register was loaded, now to buy execution
pub enum LoadedHolding {}
/// Need to explicitly state it won't pay for fees
pub enum ExplicitUnpaidRequired {}

impl XcmBuilderState for AnythingGoes {}
impl XcmBuilderState for PaymentRequired {}
impl XcmBuilderState for LoadedHolding {}
impl XcmBuilderState for ExplicitUnpaidRequired {}

/// Type used to build XCM programs
pub struct XcmBuilder<Call, S: XcmBuilderState> {
pub(crate) instructions: Vec<Instruction<Call>>,
pub state: core::marker::PhantomData<S>,
}

impl<Call> Xcm<Call> {
pub fn builder() -> XcmBuilder<Call> {
XcmBuilder::<Call>(Vec::new())
pub fn builder() -> XcmBuilder<Call, PaymentRequired> {
XcmBuilder::<Call, PaymentRequired> {
instructions: Vec::new(),
state: core::marker::PhantomData,
}
}
pub fn builder_unpaid() -> XcmBuilder<Call, ExplicitUnpaidRequired> {
XcmBuilder::<Call, ExplicitUnpaidRequired> {
instructions: Vec::new(),
state: core::marker::PhantomData,
}
}
pub fn builder_unsafe() -> XcmBuilder<Call, AnythingGoes> {
XcmBuilder::<Call, AnythingGoes> {
instructions: Vec::new(),
state: core::marker::PhantomData,
}
}
}
#builder_impl
#builder_unpaid_impl
#builder_raw_impl
};
output.into()
Ok(output)
}

fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> TokenStream2 {
fn generate_builder_raw_impl(name: &Ident, data_enum: &DataEnum) -> TokenStream2 {
let methods = data_enum.variants.iter().map(|variant| {
let variant_name = &variant.ident;
let method_name_string = &variant_name.to_string().to_snake_case();
let method_name = syn::Ident::new(&method_name_string, variant_name.span());
let docs: Vec<_> = variant
.attrs
.iter()
.filter_map(|attr| match &attr.meta {
Meta::NameValue(MetaNameValue {
value: Expr::Lit(ExprLit { lit: Lit::Str(literal), .. }),
..
}) if attr.path().is_ident("doc") => Some(literal.value()),
_ => None,
})
.map(|doc| syn::parse_str::<TokenStream2>(&format!("/// {}", doc)).unwrap())
.collect();
let docs = get_doc_comments(&variant);
let method = match &variant.fields {
Fields::Unit => {
quote! {
pub fn #method_name(mut self) -> Self {
self.0.push(#name::<Call>::#variant_name);
self.instructions.push(#name::<Call>::#variant_name);
self
}
}
Expand All @@ -81,7 +108,7 @@ fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> Tok
let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect();
quote! {
pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self {
self.0.push(#name::<Call>::#variant_name(#(#arg_names),*));
self.instructions.push(#name::<Call>::#variant_name(#(#arg_names),*));
self
}
}
Expand All @@ -91,7 +118,7 @@ fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> Tok
let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect();
quote! {
pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self {
self.0.push(#name::<Call>::#variant_name { #(#arg_names),* });
self.instructions.push(#name::<Call>::#variant_name { #(#arg_names),* });
self
}
}
Expand All @@ -103,13 +130,209 @@ fn generate_methods_for_enum(name: syn::Ident, data_enum: &syn::DataEnum) -> Tok
}
});
let output = quote! {
impl<Call> XcmBuilder<Call> {
impl<Call> XcmBuilder<Call, AnythingGoes> {
#(#methods)*

pub fn build(self) -> Xcm<Call> {
Xcm(self.0)
Xcm(self.instructions)
}
}
};
output
}

fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStream2> {
// We first require an instruction that load the holding register
let load_holding_variants = data_enum
.variants
.iter()
.map(|variant| {
let maybe_builder_attr = variant.attrs.iter().find(|attr| match attr.meta {
Meta::List(ref list) => {
return list.path.is_ident("builder");
},
_ => false,
});
let builder_attr = match maybe_builder_attr {
Some(builder) => builder.clone(),
None => return Ok(None), /* It's not going to be an instruction that loads the
* holding register */
};
let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") };
let inner_ident: Ident = syn::parse2(list.tokens.clone().into()).map_err(|_| {
Error::new_spanned(&builder_attr, "Expected `builder(loads_holding)`")
})?;
let ident_to_match: Ident = syn::parse_quote!(loads_holding);
if inner_ident == ident_to_match {
Ok(Some(variant))
} else {
Err(Error::new_spanned(&builder_attr, "Expected `builder(loads_holding)`"))
}
})
.collect::<Result<Vec<_>>>()?;

let load_holding_methods = load_holding_variants
.into_iter()
.flatten()
.map(|variant| {
let variant_name = &variant.ident;
let method_name_string = &variant_name.to_string().to_snake_case();
let method_name = syn::Ident::new(&method_name_string, variant_name.span());
let docs = get_doc_comments(&variant);
let method = match &variant.fields {
Fields::Unnamed(fields) => {
let arg_names: Vec<_> = fields
.unnamed
.iter()
.enumerate()
.map(|(index, _)| format_ident!("arg{}", index))
.collect();
let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect();
quote! {
#(#docs)*
pub fn #method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder<Call, LoadedHolding> {
let mut new_instructions = self.instructions;
new_instructions.push(#name::<Call>::#variant_name(#(#arg_names),*));
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
},
Fields::Named(fields) => {
let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect();
let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect();
quote! {
#(#docs)*
pub fn #method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder<Call, LoadedHolding> {
let mut new_instructions = self.instructions;
new_instructions.push(#name::<Call>::#variant_name { #(#arg_names),* });
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
},
_ =>
return Err(Error::new_spanned(
&variant,
"Instructions that load the holding register should take operands",
)),
};
Ok(method)
})
.collect::<std::result::Result<Vec<_>, _>>()?;

let first_impl = quote! {
impl<Call> XcmBuilder<Call, PaymentRequired> {
#(#load_holding_methods)*
}
};

// Then we require fees to be paid
let buy_execution_method = data_enum
.variants
.iter()
.find(|variant| variant.ident.to_string() == "BuyExecution")
.map_or(
Err(Error::new_spanned(&data_enum.variants, "No BuyExecution instruction")),
|variant| {
let variant_name = &variant.ident;
let method_name_string = &variant_name.to_string().to_snake_case();
let method_name = syn::Ident::new(&method_name_string, variant_name.span());
let docs = get_doc_comments(&variant);
let fields = match &variant.fields {
Fields::Named(fields) => {
let arg_names: Vec<_> =
fields.named.iter().map(|field| &field.ident).collect();
let arg_types: Vec<_> =
fields.named.iter().map(|field| &field.ty).collect();
quote! {
#(#docs)*
pub fn #method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder<Call, AnythingGoes> {
let mut new_instructions = self.instructions;
new_instructions.push(#name::<Call>::#variant_name { #(#arg_names),* });
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
},
_ =>
return Err(Error::new_spanned(
&variant,
"BuyExecution should have named fields",
)),
};
Ok(fields)
},
)?;

let second_impl = quote! {
impl<Call> XcmBuilder<Call, LoadedHolding> {
#buy_execution_method
}
};

let output = quote! {
#first_impl
#second_impl
};

Ok(output)
}

fn generate_builder_unpaid_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStream2> {
let unpaid_execution_variant = data_enum
.variants
.iter()
.find(|variant| variant.ident.to_string() == "UnpaidExecution")
.ok_or(Error::new_spanned(&data_enum.variants, "No UnpaidExecution instruction"))?;
let unpaid_execution_ident = &unpaid_execution_variant.ident;
let unpaid_execution_method_name = Ident::new(
&unpaid_execution_ident.to_string().to_snake_case(),
unpaid_execution_ident.span(),
);
let docs = get_doc_comments(&unpaid_execution_variant);
let fields = match &unpaid_execution_variant.fields {
Fields::Named(fields) => fields,
_ =>
return Err(Error::new_spanned(
&unpaid_execution_variant,
"UnpaidExecution should have named fields",
)),
};
let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect();
let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect();
Ok(quote! {
impl<Call> XcmBuilder<Call, ExplicitUnpaidRequired> {
#(#docs)*
pub fn #unpaid_execution_method_name(self, #(#arg_names: #arg_types),*) -> XcmBuilder<Call, AnythingGoes> {
let mut new_instructions = self.instructions;
new_instructions.push(#name::<Call>::#unpaid_execution_ident { #(#arg_names),* });
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
})
}

fn get_doc_comments(variant: &Variant) -> Vec<TokenStream2> {
variant
.attrs
.iter()
.filter_map(|attr| match &attr.meta {
Meta::NameValue(MetaNameValue {
value: Expr::Lit(ExprLit { lit: Lit::Str(literal), .. }),
..
}) if attr.path().is_ident("doc") => Some(literal.value()),
_ => None,
})
.map(|doc| syn::parse_str::<TokenStream2>(&format!("/// {}", doc)).unwrap())
.collect()
}
6 changes: 5 additions & 1 deletion polkadot/xcm/procedural/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! Procedural macros used in XCM.

use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};

mod builder_pattern;
mod v2;
Expand Down Expand Up @@ -56,7 +57,10 @@ pub fn impl_conversion_functions_for_junctions_v3(input: TokenStream) -> TokenSt
/// .buy_execution(fees, weight_limit)
/// .deposit_asset(assets, beneficiary)
/// .build();
#[proc_macro_derive(Builder)]
#[proc_macro_derive(Builder, attributes(builder))]
pub fn derive_builder(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
builder_pattern::derive(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
Loading