Skip to content

Commit 32e8292

Browse files
yrongacatangiu
andauthored
Snowbridge: Refactor inbound message conversion (#9510)
# Description - The current `MessageToXcm` inbound converter is somewhat verbose, with injected types that are sparse and unorganized, This change cleans up and refactors the code accordingly. (I can’t find the original comment, but I vaguely recall it being mentioned by @acatangiu in a previous PR review). - Add more tests cover some edge cases, such as claiming assets trapped on AH from a parachain. --------- Co-authored-by: Adrian Catangiu <[email protected]>
1 parent 7648b41 commit 32e8292

File tree

7 files changed

+328
-109
lines changed

7 files changed

+328
-109
lines changed

bridges/snowbridge/pallets/inbound-queue-v2/src/mock.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use hex_literal::hex;
88
use snowbridge_beacon_primitives::{
99
types::deneb, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader,
1010
};
11-
use snowbridge_core::TokenId;
12-
use snowbridge_inbound_queue_primitives::{v2::MessageToXcm, Log, Proof, VerificationError};
11+
use snowbridge_core::{ParaId, TokenId};
12+
use snowbridge_inbound_queue_primitives::{
13+
v2::{CreateAssetCallInfo, MessageToXcm},
14+
Log, Proof, VerificationError,
15+
};
1316
use sp_core::H160;
1417
use sp_runtime::{
1518
traits::{IdentityLookup, MaybeConvert},
@@ -98,16 +101,15 @@ impl<'a, AccountId: Clone + Clone> TryConvert<&'a AccountId, Location>
98101
}
99102

100103
parameter_types! {
101-
pub const EthereumNetwork: xcm::v5::NetworkId = xcm::v5::NetworkId::Ethereum { chain_id: 11155111 };
104+
pub const EthereumNetwork: NetworkId = Ethereum { chain_id: 11155111 };
102105
pub const GatewayAddress: H160 = H160(GATEWAY_ADDRESS);
103106
pub InboundQueueLocation: InteriorLocation = [PalletInstance(84)].into();
104-
pub UniversalLocation: InteriorLocation =
105-
[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1002)].into();
106-
pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),Parachain(1000)]);
107-
pub AssetHubUniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000)].into();
108107
pub SnowbridgeReward: BridgeReward = BridgeReward::Snowbridge;
109-
pub const CreateAssetCall: [u8;2] = [53, 0];
108+
pub const CreateAssetCallIndex: [u8;2] = [53, 0];
110109
pub const CreateAssetDeposit: u128 = 10_000_000_000u128;
110+
pub const LocalNetwork: NetworkId = ByGenesis(WESTEND_GENESIS_HASH);
111+
pub CreateAssetCall: CreateAssetCallInfo = CreateAssetCallInfo{call: CreateAssetCallIndex::get(),deposit: CreateAssetDeposit::get(),min_balance:1};
112+
pub AssetHubParaId: ParaId = ParaId::from(1000);
111113
}
112114

113115
impl inbound_queue_v2::Config for Test {
@@ -119,14 +121,12 @@ impl inbound_queue_v2::Config for Test {
119121
type AssetHubParaId = ConstU32<1000>;
120122
type MessageConverter = MessageToXcm<
121123
CreateAssetCall,
122-
CreateAssetDeposit,
123124
EthereumNetwork,
125+
LocalNetwork,
126+
GatewayAddress,
124127
InboundQueueLocation,
128+
AssetHubParaId,
125129
MockTokenIdConvert,
126-
GatewayAddress,
127-
UniversalLocation,
128-
AssetHubFromEthereum,
129-
AssetHubUniversalLocation,
130130
AccountId,
131131
>;
132132
#[cfg(feature = "runtime-benchmarks")]

bridges/snowbridge/primitives/inbound-queue/src/v2/converter.rs

Lines changed: 86 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{v2::LOG_TARGET, CallIndex};
77
use codec::{Decode, DecodeLimit, Encode};
88
use core::marker::PhantomData;
99
use frame_support::ensure;
10-
use snowbridge_core::TokenId;
10+
use snowbridge_core::{ParaId, TokenId};
1111
use sp_core::{Get, RuntimeDebug, H160};
1212
use sp_io::hashing::blake2_256;
1313
use sp_runtime::{traits::MaybeConvert, MultiAddress};
@@ -19,8 +19,6 @@ use xcm::{
1919
use xcm_builder::ExternalConsensusLocationsConverterFor;
2020
use xcm_executor::traits::ConvertLocation;
2121

22-
const MINIMUM_DEPOSIT: u128 = 1;
23-
2422
/// Topic prefix used for generating unique identifiers for messages
2523
const INBOUND_QUEUE_TOPIC_PREFIX: &str = "SnowbridgeInboundQueueV2";
2624

@@ -47,67 +45,78 @@ pub enum AssetTransfer {
4745
ReserveWithdraw(Asset),
4846
}
4947

48+
#[derive(Clone, RuntimeDebug, Encode)]
49+
pub struct CreateAssetCallInfo {
50+
pub call: CallIndex,
51+
pub deposit: u128,
52+
pub min_balance: u128,
53+
}
54+
55+
pub struct AssetHubUniversal<LocalNetwork, AssetHubParaId>(
56+
PhantomData<(LocalNetwork, AssetHubParaId)>,
57+
);
58+
impl<LocalNetwork, AssetHubParaId> Get<InteriorLocation>
59+
for AssetHubUniversal<LocalNetwork, AssetHubParaId>
60+
where
61+
LocalNetwork: Get<NetworkId>,
62+
AssetHubParaId: Get<ParaId>,
63+
{
64+
fn get() -> InteriorLocation {
65+
[GlobalConsensus(LocalNetwork::get()), Parachain(AssetHubParaId::get().into())].into()
66+
}
67+
}
68+
5069
/// Concrete implementation of `ConvertMessage`
5170
pub struct MessageToXcm<
5271
CreateAssetCall,
53-
CreateAssetDeposit,
5472
EthereumNetwork,
73+
LocalNetwork,
74+
GatewayProxyAddress,
5575
InboundQueueLocation,
76+
AssetHubParaId,
5677
ConvertAssetId,
57-
GatewayProxyAddress,
58-
EthereumUniversalLocation,
59-
AssetHubFromEthereum,
60-
AssetHubUniversalLocation,
6178
AccountId,
6279
> {
6380
_phantom: PhantomData<(
6481
CreateAssetCall,
65-
CreateAssetDeposit,
6682
EthereumNetwork,
83+
LocalNetwork,
84+
GatewayProxyAddress,
6785
InboundQueueLocation,
86+
AssetHubParaId,
6887
ConvertAssetId,
69-
GatewayProxyAddress,
70-
EthereumUniversalLocation,
71-
AssetHubFromEthereum,
72-
AssetHubUniversalLocation,
7388
AccountId,
7489
)>,
7590
}
7691

7792
impl<
7893
CreateAssetCall,
79-
CreateAssetDeposit,
8094
EthereumNetwork,
95+
LocalNetwork,
96+
GatewayProxyAddress,
8197
InboundQueueLocation,
98+
AssetHubParaId,
8299
ConvertAssetId,
83-
GatewayProxyAddress,
84-
EthereumUniversalLocation,
85-
AssetHubFromEthereum,
86-
AssetHubUniversalLocation,
87100
AccountId,
88101
>
89102
MessageToXcm<
90103
CreateAssetCall,
91-
CreateAssetDeposit,
92104
EthereumNetwork,
105+
LocalNetwork,
106+
GatewayProxyAddress,
93107
InboundQueueLocation,
108+
AssetHubParaId,
94109
ConvertAssetId,
95-
GatewayProxyAddress,
96-
EthereumUniversalLocation,
97-
AssetHubFromEthereum,
98-
AssetHubUniversalLocation,
99110
AccountId,
100111
>
101112
where
102-
CreateAssetCall: Get<CallIndex>,
103-
CreateAssetDeposit: Get<u128>,
113+
CreateAssetCall: Get<CreateAssetCallInfo>,
104114
EthereumNetwork: Get<NetworkId>,
115+
LocalNetwork: Get<NetworkId>,
116+
GatewayProxyAddress: Get<H160>,
105117
InboundQueueLocation: Get<InteriorLocation>,
118+
AssetHubParaId: Get<ParaId>,
106119
ConvertAssetId: MaybeConvert<TokenId, Location>,
107-
GatewayProxyAddress: Get<H160>,
108-
EthereumUniversalLocation: Get<InteriorLocation>,
109-
AssetHubFromEthereum: Get<Location>,
110-
AssetHubUniversalLocation: Get<InteriorLocation>,
111120
AccountId: Into<[u8; 32]> + From<[u8; 32]> + Clone,
112121
{
113122
/// Parse the message into an intermediate form, with all fields decoded
@@ -163,12 +172,21 @@ where
163172
assets.push(AssetTransfer::ReserveDeposit(asset));
164173
},
165174
EthereumAsset::ForeignTokenERC20 { token_id, value } => {
166-
let asset_loc = ConvertAssetId::maybe_convert(*token_id)
175+
let asset_location = ConvertAssetId::maybe_convert(*token_id)
167176
.ok_or(ConvertMessageError::InvalidAsset)?;
168-
let reanchored_asset_loc = asset_loc
169-
.reanchored(&AssetHubFromEthereum::get(), &EthereumUniversalLocation::get())
177+
let asset_hub_from_ethereum: Location = Location::new(
178+
1,
179+
[
180+
GlobalConsensus(LocalNetwork::get()),
181+
Parachain(AssetHubParaId::get().into()),
182+
],
183+
);
184+
let ethereum_universal: InteriorLocation =
185+
[GlobalConsensus(EthereumNetwork::get())].into();
186+
let reanchored_asset_location = asset_location
187+
.reanchored(&asset_hub_from_ethereum, &ethereum_universal)
170188
.map_err(|_| ConvertMessageError::CannotReanchor)?;
171-
let asset: Asset = (reanchored_asset_loc, *value).into();
189+
let asset: Asset = (reanchored_asset_location, *value).into();
172190
assets.push(AssetTransfer::ReserveWithdraw(asset));
173191
},
174192
}
@@ -194,9 +212,10 @@ where
194212
/// Get sovereign account of Ethereum on Asset Hub.
195213
fn bridge_owner() -> Result<AccountId, ConvertMessageError> {
196214
let account =
197-
ExternalConsensusLocationsConverterFor::<AssetHubUniversalLocation, AccountId>::convert_location(
198-
&Location::new(2, [GlobalConsensus(EthereumNetwork::get())]),
199-
)
215+
ExternalConsensusLocationsConverterFor::<
216+
AssetHubUniversal<LocalNetwork, AssetHubParaId>,
217+
AccountId,
218+
>::convert_location(&Location::new(2, [GlobalConsensus(EthereumNetwork::get())]))
200219
.ok_or(ConvertMessageError::CannotReanchor)?;
201220

202221
Ok(account)
@@ -212,12 +231,13 @@ where
212231
claimer: Location,
213232
) -> Result<Xcm<()>, ConvertMessageError> {
214233
let dot_asset = Location::new(1, Here);
215-
let dot_fee: xcm::prelude::Asset = (dot_asset, CreateAssetDeposit::get()).into();
234+
let dot_fee: xcm::prelude::Asset = (dot_asset, CreateAssetCall::get().deposit).into();
216235

217236
let eth_asset: xcm::prelude::Asset =
218237
(Location::new(2, [GlobalConsensus(EthereumNetwork::get())]), eth_value).into();
219238

220-
let create_call_index: [u8; 2] = CreateAssetCall::get();
239+
let create_call_index: [u8; 2] = CreateAssetCall::get().call;
240+
let create_min_blance: u128 = CreateAssetCall::get().min_balance;
221241

222242
let asset_id = Location::new(
223243
2,
@@ -230,6 +250,7 @@ where
230250
match network {
231251
super::message::Network::Polkadot => Ok(Self::make_create_asset_xcm_for_polkadot(
232252
create_call_index,
253+
create_min_blance,
233254
asset_id,
234255
bridge_owner,
235256
dot_fee,
@@ -242,6 +263,7 @@ where
242263
/// Construct the asset creation XCM for the Polkdot network.
243264
fn make_create_asset_xcm_for_polkadot(
244265
create_call_index: [u8; 2],
266+
create_min_blance: u128,
245267
asset_id: Location,
246268
bridge_owner: AccountId,
247269
dot_fee_asset: xcm::prelude::Asset,
@@ -270,7 +292,7 @@ where
270292
create_call_index,
271293
asset_id.clone(),
272294
MultiAddress::<[u8; 32], ()>::Id(bridge_owner_bytes.into()),
273-
MINIMUM_DEPOSIT,
295+
create_min_blance,
274296
)
275297
.encode()
276298
.into(),
@@ -301,39 +323,33 @@ where
301323
}
302324

303325
impl<
304-
CreateAssetCall,
305-
CreateAssetDeposit,
326+
CreateAsset,
306327
EthereumNetwork,
328+
LocalNetwork,
329+
GatewayProxyAddress,
307330
InboundQueueLocation,
331+
AssetHubParaId,
308332
ConvertAssetId,
309-
GatewayProxyAddress,
310-
EthereumUniversalLocation,
311-
AssetHubFromEthereum,
312-
AssetHubUniversalLocation,
313333
AccountId,
314334
> ConvertMessage
315335
for MessageToXcm<
316-
CreateAssetCall,
317-
CreateAssetDeposit,
336+
CreateAsset,
318337
EthereumNetwork,
338+
LocalNetwork,
339+
GatewayProxyAddress,
319340
InboundQueueLocation,
341+
AssetHubParaId,
320342
ConvertAssetId,
321-
GatewayProxyAddress,
322-
EthereumUniversalLocation,
323-
AssetHubFromEthereum,
324-
AssetHubUniversalLocation,
325343
AccountId,
326344
>
327345
where
328-
CreateAssetCall: Get<CallIndex>,
329-
CreateAssetDeposit: Get<u128>,
346+
CreateAsset: Get<CreateAssetCallInfo>,
330347
EthereumNetwork: Get<NetworkId>,
348+
LocalNetwork: Get<NetworkId>,
349+
GatewayProxyAddress: Get<H160>,
331350
InboundQueueLocation: Get<InteriorLocation>,
351+
AssetHubParaId: Get<ParaId>,
332352
ConvertAssetId: MaybeConvert<TokenId, Location>,
333-
GatewayProxyAddress: Get<H160>,
334-
EthereumUniversalLocation: Get<InteriorLocation>,
335-
AssetHubFromEthereum: Get<Location>,
336-
AssetHubUniversalLocation: Get<InteriorLocation>,
337353
AccountId: Into<[u8; 32]> + From<[u8; 32]> + Clone,
338354
{
339355
fn convert(message: Message) -> Result<Xcm<()>, ConvertMessageError> {
@@ -405,17 +421,19 @@ mod tests {
405421
const GATEWAY_ADDRESS: [u8; 20] = hex!["eda338e4dc46038493b885327842fd3e301cab39"];
406422

407423
parameter_types! {
408-
pub const EthereumNetwork: xcm::v5::NetworkId = xcm::v5::NetworkId::Ethereum { chain_id: 1 };
424+
pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 1 };
425+
pub const LocalNetwork: NetworkId = NetworkId::Polkadot;
409426
pub const GatewayAddress: H160 = H160(GATEWAY_ADDRESS);
410427
pub InboundQueueLocation: InteriorLocation = [PalletInstance(84)].into();
411428
pub EthereumUniversalLocation: InteriorLocation =
412429
[GlobalConsensus(EthereumNetwork::get())].into();
413-
pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(Polkadot),Parachain(1000)]);
414-
pub AssetHubUniversalLocation: InteriorLocation = [GlobalConsensus(Polkadot),Parachain(1000)].into();
415-
pub const CreateAssetCall: [u8;2] = [53, 0];
430+
pub AssetHubParaId: ParaId = 1000.into();
431+
pub const CreateAssetCallIndex: [u8;2] = [53, 0];
416432
pub const CreateAssetDeposit: u128 = 10_000_000_000u128;
433+
pub const CreateAssetMinBalance: u128 = 1;
417434
pub EthereumLocation: Location = Location::new(2,EthereumUniversalLocation::get());
418435
pub BridgeHubContext: InteriorLocation = [GlobalConsensus(Polkadot),Parachain(1002)].into();
436+
pub CreateAssetCall: CreateAssetCallInfo = CreateAssetCallInfo{call: CreateAssetCallIndex::get(),deposit: CreateAssetDeposit::get(),min_balance: CreateAssetMinBalance::get()};
419437
}
420438

421439
pub struct MockFailedTokenConvert;
@@ -427,27 +445,23 @@ mod tests {
427445

428446
type Converter = MessageToXcm<
429447
CreateAssetCall,
430-
CreateAssetDeposit,
431448
EthereumNetwork,
449+
LocalNetwork,
450+
GatewayAddress,
432451
InboundQueueLocation,
452+
AssetHubParaId,
433453
LocationIdConvert,
434-
GatewayAddress,
435-
EthereumUniversalLocation,
436-
AssetHubFromEthereum,
437-
AssetHubUniversalLocation,
438454
[u8; 32],
439455
>;
440456

441457
type ConverterFailing = MessageToXcm<
442458
CreateAssetCall,
443-
CreateAssetDeposit,
444459
EthereumNetwork,
460+
LocalNetwork,
461+
GatewayAddress,
445462
InboundQueueLocation,
463+
AssetHubParaId,
446464
MockFailedTokenConvert,
447-
GatewayAddress,
448-
EthereumUniversalLocation,
449-
AssetHubFromEthereum,
450-
AssetHubUniversalLocation,
451465
[u8; 32],
452466
>;
453467

@@ -746,7 +760,7 @@ mod tests {
746760

747761
// actual claimer should default to Snowbridge sovereign account
748762
let bridge_owner = ExternalConsensusLocationsConverterFor::<
749-
AssetHubUniversalLocation,
763+
AssetHubUniversal<LocalNetwork, AssetHubParaId>,
750764
[u8; 32],
751765
>::convert_location(&Location::new(
752766
2,

0 commit comments

Comments
 (0)