Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow clear_origin in safe xcm builder #4777

Merged
27 changes: 27 additions & 0 deletions polkadot/xcm/procedural/src/builder_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,32 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStre
}
};

// Some operations are allowed after the holding register is loaded
let allowed_after_load_holding_methods: Vec<TokenStream2> = data_enum
.variants
.iter()
.filter(|variant| variant.ident == "ClearOrigin")
.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::Unit => {
quote! {
#(#docs)*
pub fn #method_name(mut self) -> XcmBuilder<Call, LoadedHolding> {
self.instructions.push(#name::<Call>::#variant_name);
self
}
}
},
_ => return Err(Error::new_spanned(variant, "ClearOrigin should have no fields")),
};
Ok(method)
})
.collect::<std::result::Result<Vec<_>, _>>()?;

// Then we require fees to be paid
let buy_execution_method = data_enum
.variants
Expand Down Expand Up @@ -276,6 +302,7 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStre

let second_impl = quote! {
impl<Call> XcmBuilder<Call, LoadedHolding> {
#(#allowed_after_load_holding_methods)*
#buy_execution_method
}
};
Expand Down
21 changes: 21 additions & 0 deletions polkadot/xcm/procedural/tests/builder_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,24 @@ fn default_builder_requires_buy_execution() {
])
);
}

#[test]
fn default_builder_allows_clear_origin_before_buy_execution() {
let asset: Asset = (Here, 100u128).into();
let beneficiary: Location = [0u8; 32].into();
let message: Xcm<()> = Xcm::builder()
.receive_teleported_asset(asset.clone())
.clear_origin()
.buy_execution(asset.clone(), Unlimited)
.deposit_asset(asset.clone(), beneficiary.clone())
.build();
assert_eq!(
message,
Xcm(vec![
ReceiveTeleportedAsset(asset.clone().into()),
ClearOrigin,
BuyExecution { fees: asset.clone(), weight_limit: Unlimited },
DepositAsset { assets: asset.into(), beneficiary },
])
);
}
27 changes: 27 additions & 0 deletions prdoc/pr_4777.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: XCM builder pattern allows clear_origin before buy_execution.

doc:
- audience: Runtime Dev
description: |
Added clear_origin as an allowed command after commands that load the holdings register, in the safe xcm builder.
Previously, although it's logically allowed, an XCM could not be built like this:
```rust
let xcm = Xcm::builder()
.withdraw_asset((Parent, 100u128))
.clear_origin()
.buy_execution((Parent, 1u128))
.deposit_asset(All, [0u8; 32])
.build();
```
franciscoaguirre marked this conversation as resolved.
Show resolved Hide resolved
You had to use the unsafe_builder.
Now, it's allowed using the default builder.

crates:
- name: "xcm-procedural"
bump: minor
- name: "staging-xcm"
bump: minor

Loading