@@ -53,7 +53,7 @@ use xcm_executor::traits::WeightBounds;
5353
5454pub use module:: * ;
5555use orml_traits:: {
56- location:: { Parse , Reserve } ,
56+ location:: { Reserve , ASSET_HUB_ID } ,
5757 xcm_transfer:: { Transferred , XtokensWeightInfo } ,
5858 GetByKey , RateLimiter , XcmTransfer ,
5959} ;
@@ -71,6 +71,19 @@ enum TransferKind {
7171}
7272use TransferKind :: * ;
7373
74+ #[ derive(
75+ scale_info:: TypeInfo , Default , Encode , Decode , Clone , Eq , PartialEq , Debug , MaxEncodedLen , DecodeWithMemTracking ,
76+ ) ]
77+ pub enum MigrationPhase {
78+ /// Not started
79+ #[ default]
80+ NotStarted ,
81+ /// Started
82+ InProgress ,
83+ /// Completed
84+ Completed ,
85+ }
86+
7487#[ frame_support:: pallet]
7588pub mod module {
7689 use super :: * ;
@@ -135,8 +148,14 @@ pub mod module {
135148 /// The id of the RateLimiter.
136149 #[ pallet:: constant]
137150 type RateLimiterId : Get < <Self :: RateLimiter as RateLimiter >:: RateLimiterId > ;
151+
152+ /// The origin that can change the migration phase.
153+ type MigrationPhaseUpdateOrigin : EnsureOrigin < Self :: RuntimeOrigin > ;
138154 }
139155
156+ #[ pallet:: storage]
157+ pub type MigrationStatus < T : Config > = StorageValue < _ , MigrationPhase , ValueQuery > ;
158+
140159 #[ pallet:: event]
141160 #[ pallet:: generate_deposit( fn deposit_event) ]
142161 pub enum Event < T : Config > {
@@ -147,6 +166,8 @@ pub mod module {
147166 fee : Asset ,
148167 dest : Location ,
149168 } ,
169+ /// Migration phase changed.
170+ MigrationPhaseChanged { migration_phase : MigrationPhase } ,
150171 }
151172
152173 #[ pallet:: error]
@@ -394,6 +415,18 @@ pub mod module {
394415
395416 Self :: do_transfer_assets ( who, assets. clone ( ) , fee. clone ( ) , dest, dest_weight_limit) . map ( |_| ( ) )
396417 }
418+
419+ #[ pallet:: call_index( 6 ) ]
420+ #[ pallet:: weight( frame_support:: weights:: Weight :: from_parts( 10000 , 0 ) ) ]
421+ pub fn set_migration_phase ( origin : OriginFor < T > , migration_phase : MigrationPhase ) -> DispatchResult {
422+ T :: MigrationPhaseUpdateOrigin :: ensure_origin ( origin) ?;
423+
424+ MigrationStatus :: < T > :: set ( migration_phase. clone ( ) ) ;
425+
426+ Self :: deposit_event ( Event :: < T > :: MigrationPhaseChanged { migration_phase } ) ;
427+
428+ Ok ( ( ) )
429+ }
397430 }
398431
399432 impl < T : Config > Pallet < T > {
@@ -565,7 +598,7 @@ pub mod module {
565598 if asset_len > 1 && fee_reserve != non_fee_reserve {
566599 // Current only support `ToReserve` with relay-chain asset as fee. other case
567600 // like `NonReserve` or `SelfReserve` with relay-chain fee is not support.
568- ensure ! ( non_fee_reserve == dest . chain_part( ) , Error :: <T >:: InvalidAsset ) ;
601+ ensure ! ( non_fee_reserve == Self :: chain_part( & dest ) , Error :: <T >:: InvalidAsset ) ;
569602
570603 let reserve_location = non_fee_reserve. clone ( ) . ok_or ( Error :: < T > :: AssetHasNoReserve ) ?;
571604 let min_xcm_fee = T :: MinXcmFee :: get ( & reserve_location) . ok_or ( Error :: < T > :: MinXcmFeeNotDefined ) ?;
@@ -590,7 +623,7 @@ pub mod module {
590623
591624 let mut override_recipient = T :: SelfLocation :: get ( ) ;
592625 if override_recipient == Location :: here ( ) {
593- let dest_chain_part = dest . chain_part ( ) . ok_or ( Error :: < T > :: InvalidDest ) ?;
626+ let dest_chain_part = Self :: chain_part ( & dest ) . ok_or ( Error :: < T > :: InvalidDest ) ?;
594627 let ancestry = T :: UniversalLocation :: get ( ) ;
595628 let _ = override_recipient
596629 . reanchor ( & dest_chain_part, & ancestry)
@@ -817,7 +850,7 @@ pub mod module {
817850
818851 /// Ensure has the `dest` has chain part and recipient part.
819852 fn ensure_valid_dest ( dest : & Location ) -> Result < ( Location , Location ) , DispatchError > {
820- if let ( Some ( dest) , Some ( recipient) ) = ( dest . chain_part ( ) , dest . non_chain_part ( ) ) {
853+ if let ( Some ( dest) , Some ( recipient) ) = ( Self :: chain_part ( & dest ) , Self :: non_chain_part ( & dest ) ) {
821854 Ok ( ( dest, recipient) )
822855 } else {
823856 Err ( Error :: < T > :: InvalidDest . into ( ) )
@@ -863,6 +896,41 @@ pub mod module {
863896 let asset = assets. get ( reserve_idx) ;
864897 asset. and_then ( T :: ReserveProvider :: reserve)
865898 }
899+
900+ /// Returns the "chain" location part. It could be parent, sibling
901+ /// parachain, or child parachain.
902+ pub fn chain_part ( location : & Location ) -> Option < Location > {
903+ match ( location. parents , location. first_interior ( ) ) {
904+ // sibling parachain
905+ ( 1 , Some ( Parachain ( id) ) ) => Some ( Location :: new ( 1 , [ Parachain ( * id) ] ) ) ,
906+ // parent
907+ ( 1 , _) => match MigrationStatus :: < T > :: get ( ) {
908+ // RelayChain
909+ MigrationPhase :: NotStarted => Some ( Location :: parent ( ) ) ,
910+ // Disable transfer when migration is in progress
911+ MigrationPhase :: InProgress => None ,
912+ // AssetHub
913+ MigrationPhase :: Completed => Some ( Location :: new ( 1 , [ Parachain ( ASSET_HUB_ID ) ] ) ) ,
914+ } ,
915+ // children parachain
916+ ( 0 , Some ( Parachain ( id) ) ) => Some ( Location :: new ( 0 , [ Parachain ( * id) ] ) ) ,
917+ _ => None ,
918+ }
919+ }
920+
921+ /// Returns "non-chain" location part.
922+ pub fn non_chain_part ( location : & Location ) -> Option < Location > {
923+ let mut junctions = location. interior ( ) . clone ( ) ;
924+ while is_chain_junction ( junctions. first ( ) ) {
925+ let _ = junctions. take_first ( ) ;
926+ }
927+
928+ if junctions != Here {
929+ Some ( Location :: new ( 0 , junctions) )
930+ } else {
931+ None
932+ }
933+ }
866934 }
867935
868936 pub struct XtokensWeight < T > ( PhantomData < T > ) ;
@@ -1066,3 +1134,32 @@ fn subtract_fee(asset: &Asset, amount: u128) -> Asset {
10661134 id : asset. id . clone ( ) ,
10671135 }
10681136}
1137+
1138+ fn is_chain_junction ( junction : Option < & Junction > ) -> bool {
1139+ matches ! ( junction, Some ( Parachain ( _) ) )
1140+ }
1141+
1142+ // Provide reserve in absolute path view
1143+ pub struct AbsoluteReserveProviderMigrationPhase < T > ( PhantomData < T > ) ;
1144+
1145+ impl < T : Config > Reserve for AbsoluteReserveProviderMigrationPhase < T > {
1146+ fn reserve ( asset : & Asset ) -> Option < Location > {
1147+ let AssetId ( location) = & asset. id ;
1148+ Pallet :: < T > :: chain_part ( location)
1149+ }
1150+ }
1151+
1152+ // Provide reserve in relative path view
1153+ // Self tokens are represeneted as Here
1154+ pub struct RelativeReserveProviderMigrationPhase < T > ( PhantomData < T > ) ;
1155+
1156+ impl < T : Config > Reserve for RelativeReserveProviderMigrationPhase < T > {
1157+ fn reserve ( asset : & Asset ) -> Option < Location > {
1158+ let AssetId ( location) = & asset. id ;
1159+ if location. parents == 0 && !is_chain_junction ( location. first_interior ( ) ) {
1160+ Some ( Location :: here ( ) )
1161+ } else {
1162+ Pallet :: < T > :: chain_part ( location)
1163+ }
1164+ }
1165+ }
0 commit comments