Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Commit

Permalink
Validate MultiLocation for asset-registry (#224)
Browse files Browse the repository at this point in the history
* Validate location for register_reserve_asset

* fmt

* fmt

* fmt

* validator refactor

* fmt
  • Loading branch information
valentinfernandez1 committed Jun 12, 2023
1 parent 855f102 commit f42817b
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 75 deletions.
37 changes: 28 additions & 9 deletions pallets/asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ pub mod pallet {
use frame_system::pallet_prelude::*;

use xcm::latest::{
Junction::{GeneralIndex, PalletInstance, Parachain},
Junctions, MultiLocation,
Junction::{AccountId32, AccountKey20, GeneralIndex, PalletInstance},
MultiLocation,
};

#[pallet::pallet]
Expand Down Expand Up @@ -97,13 +97,7 @@ pub mod pallet {

// verify MultiLocation is valid
ensure!(
matches!(
asset_multi_location,
MultiLocation {
parents: 1,
interior: Junctions::X3(Parachain(_), PalletInstance(_), GeneralIndex(_))
}
),
Self::valid_asset_location(&asset_multi_location),
Error::<T>::WrongMultiLocation
);

Expand Down Expand Up @@ -137,6 +131,31 @@ pub mod pallet {
}
}

impl<T: Config> Pallet<T> {
//Validates that the location points to an asset (Native, Frame based, Erc20) as described
// in the xcm-format: https://github.com/paritytech/xcm-format#concrete-identifiers
fn valid_asset_location(location: &MultiLocation) -> bool {
let (split_multilocation, last_junction) = location.clone().split_last_interior();

let check = matches!(
last_junction,
Some(AccountId32 { .. }) |
Some(AccountKey20 { .. }) |
Some(PalletInstance(_)) |
None
);

check |
match last_junction {
Some(GeneralIndex(_)) => {
let penultimate = split_multilocation.last();
matches!(penultimate, Some(PalletInstance(_)))
},
_ => false,
}
}
}

impl<T: Config> xcm_primitives::AssetMultiLocationGetter<AssetIdOf<T>> for Pallet<T> {
fn get_asset_multi_location(asset_id: AssetIdOf<T>) -> Option<MultiLocation> {
AssetIdMultiLocation::<T>::get(asset_id)
Expand Down
235 changes: 169 additions & 66 deletions pallets/asset-registry/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,84 +12,187 @@ const STATEMINE_ASSET_MULTI_LOCATION: MultiLocation = MultiLocation {
),
};

#[test]
fn register_reserve_asset_works() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
));

assert_eq!(
AssetIdMultiLocation::<Test>::get(LOCAL_ASSET_ID),
Some(STATEMINE_ASSET_MULTI_LOCATION)
);
assert_eq!(
AssetMultiLocationId::<Test>::get(STATEMINE_ASSET_MULTI_LOCATION),
Some(LOCAL_ASSET_ID)
);
});
}
mod register_reserve_assest {
use super::*;

#[test]
fn register_reserve_asset_works() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
));

assert_eq!(
AssetIdMultiLocation::<Test>::get(LOCAL_ASSET_ID),
Some(STATEMINE_ASSET_MULTI_LOCATION)
);
assert_eq!(
AssetMultiLocationId::<Test>::get(STATEMINE_ASSET_MULTI_LOCATION),
Some(LOCAL_ASSET_ID)
);
});
}

#[test]
fn cannot_register_unexisting_asset() {
new_test_ext().execute_with(|| {
let unexisting_asset_id = 9999;
#[test]
fn cannot_register_unexisting_asset() {
new_test_ext().execute_with(|| {
let unexisting_asset_id = 9999;

assert_noop!(
AssetRegistry::register_reserve_asset(
assert_noop!(
AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
unexisting_asset_id,
STATEMINE_ASSET_MULTI_LOCATION,
),
Error::<Test>::AssetDoesNotExist
);
});
}

#[test]
fn cannot_double_register() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
unexisting_asset_id,
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
));

assert_noop!(
AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
),
Error::<Test>::AssetAlreadyRegistered
);
});
}

#[test]
fn valid_locations_succced() {
let native_frame_based_currency =
MultiLocation { parents: 1, interior: X2(Parachain(1000), PalletInstance(1)) };
let multiasset_pallet_instance = MultiLocation {
parents: 1,
interior: X3(Parachain(1000), PalletInstance(1), GeneralIndex(2)),
};
let relay_native_currency = MultiLocation { parents: 1, interior: Junctions::Here };
let erc20_frame_sm_asset = MultiLocation {
parents: 1,
interior: X3(
Parachain(1000),
PalletInstance(2),
AccountId32 { network: Any, id: [0; 32] },
),
Error::<Test>::AssetDoesNotExist
);
});
}
};
let erc20_ethereum_sm_asset = MultiLocation {
parents: 1,
interior: X2(Parachain(2000), AccountKey20 { network: Any, key: [0; 20] }),
};

#[test]
fn cannot_double_register() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
));

assert_noop!(
AssetRegistry::register_reserve_asset(
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
native_frame_based_currency,
));
});
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
multiasset_pallet_instance,
));
});
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
relay_native_currency,
));
});
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
erc20_frame_sm_asset,
));
});
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
erc20_ethereum_sm_asset,
));
});
}

#[test]
fn invalid_locations_fail() {
let governance_location = MultiLocation {
parents: 1,
interior: X2(
Parachain(1000),
Plurality { id: BodyId::Executive, part: BodyPart::Voice },
),
Error::<Test>::AssetAlreadyRegistered
);
});
};
let invalid_general_index =
MultiLocation { parents: 1, interior: X2(Parachain(1000), GeneralIndex(1u128)) };

new_test_ext().execute_with(|| {
assert_noop!(
AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
governance_location,
),
Error::<Test>::WrongMultiLocation
);

assert_noop!(
AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
invalid_general_index,
),
Error::<Test>::WrongMultiLocation
);
})
}
}

#[test]
fn unregister_reserve_asset_works() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
));
mod unregister_reserve_asset {
use super::*;

assert_ok!(AssetRegistry::unregister_reserve_asset(RuntimeOrigin::root(), LOCAL_ASSET_ID));
#[test]
fn unregister_reserve_asset_works() {
new_test_ext().execute_with(|| {
assert_ok!(AssetRegistry::register_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID,
STATEMINE_ASSET_MULTI_LOCATION,
));

assert!(AssetIdMultiLocation::<Test>::get(LOCAL_ASSET_ID).is_none());
assert!(AssetMultiLocationId::<Test>::get(STATEMINE_ASSET_MULTI_LOCATION).is_none());
});
}
assert_ok!(AssetRegistry::unregister_reserve_asset(
RuntimeOrigin::root(),
LOCAL_ASSET_ID
));

assert!(AssetIdMultiLocation::<Test>::get(LOCAL_ASSET_ID).is_none());
assert!(AssetMultiLocationId::<Test>::get(STATEMINE_ASSET_MULTI_LOCATION).is_none());
});
}

#[test]
fn cannot_register_unregistered_asset() {
new_test_ext().execute_with(|| {
assert_noop!(
AssetRegistry::unregister_reserve_asset(RuntimeOrigin::root(), LOCAL_ASSET_ID),
Error::<Test>::AssetIsNotRegistered
);
});
#[test]
fn cannot_register_unregistered_asset() {
new_test_ext().execute_with(|| {
assert_noop!(
AssetRegistry::unregister_reserve_asset(RuntimeOrigin::root(), LOCAL_ASSET_ID),
Error::<Test>::AssetIsNotRegistered
);
});
}
}

0 comments on commit f42817b

Please sign in to comment.