Newer
Older
ExpectTransactStatus(transact_status) => {
ensure!(self.transact_status == transact_status, XcmError::ExpectationFalse);
Ok(())
},
QueryPallet { module_name, response_info } => {
let pallets = Config::PalletInstancesInfo::infos()
.into_iter()
.filter(|x| x.module_name.as_bytes() == &module_name[..])
.map(|x| {
PalletInfo::new(
x.index as u32,
x.name.as_bytes().into(),
x.module_name.as_bytes().into(),
x.crate_version.major as u32,
x.crate_version.minor as u32,
x.crate_version.patch as u32,
)
})
.collect::<Result<Vec<_>, XcmError>>()?;
let QueryResponseInfo { destination, query_id, max_weight } = response_info;
let response =
Response::PalletsInfo(pallets.try_into().map_err(|_| XcmError::Overflow)?);
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
let querier = Self::to_querier(self.cloned_origin(), &destination)?;
let instruction = QueryResponse { query_id, response, max_weight, querier };
let message = Xcm(vec![instruction]);
self.send(destination, message, FeeReason::QueryPallet)?;
Ok(())
},
ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
let pallet = Config::PalletInstancesInfo::infos()
.into_iter()
.find(|x| x.index == index as usize)
.ok_or(XcmError::PalletNotFound)?;
ensure!(pallet.name.as_bytes() == &name[..], XcmError::NameMismatch);
ensure!(pallet.module_name.as_bytes() == &module_name[..], XcmError::NameMismatch);
let major = pallet.crate_version.major as u32;
ensure!(major == crate_major, XcmError::VersionIncompatible);
let minor = pallet.crate_version.minor as u32;
ensure!(minor >= min_crate_minor, XcmError::VersionIncompatible);
Ok(())
},
ReportTransactStatus(response_info) => {
self.respond(
self.cloned_origin(),
Response::DispatchResult(self.transact_status.clone()),
response_info,
FeeReason::Report,
)?;
Ok(())
},
ClearTransactStatus => {
self.transact_status = Default::default();
Ok(())
},
UniversalOrigin(new_global) => {
let universal_location = Config::UniversalLocation::get();
ensure!(universal_location.first() != Some(&new_global), XcmError::InvalidLocation);
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
let origin_xform = (origin, new_global);
let ok = Config::UniversalAliases::contains(&origin_xform);
ensure!(ok, XcmError::InvalidLocation);
let (_, new_global) = origin_xform;
let new_origin = Junctions::from([new_global]).relative_to(&universal_location);
self.context.origin = Some(new_origin);
Ok(())
},
ExportMessage { network, destination, xcm } => {
// The actual message sent to the bridge for forwarding is prepended with
// `UniversalOrigin` and `DescendOrigin` in order to ensure that the message is
// executed with this Origin.
// Prepend the desired message with instructions which effectively rewrite the
// origin.
//
// This only works because the remote chain empowers the bridge
// to speak for the local network.
let origin = self.context.origin.as_ref().ok_or(XcmError::BadOrigin)?.clone();
let universal_source = Config::UniversalLocation::get()
.within_global(origin)
.map_err(|()| XcmError::Unanchored)?;
let hash = (self.origin_ref(), &destination).using_encoded(blake2_128);
let channel = u32::decode(&mut hash.as_ref()).unwrap_or(0);
// Hash identifies the lane on the exporter which we use. We use the pairwise
// combination of the origin and destination to ensure origin/destination pairs
// will generally have their own lanes.
let (ticket, fee) = validate_export::<Config::MessageExporter>(
network,
channel,
universal_source,
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
self.take_fee(fee, FeeReason::Export { network, destination })?;
let _ = Config::MessageExporter::deliver(ticket).defensive_proof(
"`deliver` called immediately after `validate_export`; \
`take_fee` does not affect the validity of the ticket; qed",
);
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
let (remote_asset, context) = Self::try_reanchor(asset.clone(), &unlocker)?;
let lock_ticket =
Config::AssetLocker::prepare_lock(unlocker.clone(), asset, origin.clone())?;
let owner = origin
.reanchored(&unlocker, &context)
.map_err(|_| XcmError::ReanchorFailed)?;
let msg = Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner }]);
let (ticket, price) = validate_send::<Config::XcmSender>(unlocker, msg)?;
self.take_fee(price, FeeReason::LockAsset)?;
lock_ticket.enact()?;
Config::XcmSender::deliver(ticket)?;
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
Config::AssetLocker::prepare_unlock(origin, asset, target)?.enact()?;
Ok(())
},
NoteUnlockable { asset, owner } => {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
Config::AssetLocker::note_unlockable(origin, asset, owner)?;
Ok(())
},
RequestUnlock { asset, locker } => {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
let remote_asset = Self::try_reanchor(asset.clone(), &locker)?.0;
let remote_target = Self::try_reanchor(origin.clone(), &locker)?.0;
let reduce_ticket = Config::AssetLocker::prepare_reduce_unlockable(
locker.clone(),
asset,
origin.clone(),
)?;
let msg =
Xcm::<()>(vec![UnlockAsset { asset: remote_asset, target: remote_target }]);
let (ticket, price) = validate_send::<Config::XcmSender>(locker, msg)?;
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
self.take_fee(price, FeeReason::RequestUnlock)?;
reduce_ticket.enact()?;
Config::XcmSender::deliver(ticket)?;
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
let old_holding = self.holding.clone();
let result = (|| -> Result<(), XcmError> {
self.ensure_can_subsume_assets(want.len())?;
let exchange_result = Config::AssetExchanger::exchange_asset(
self.origin_ref(),
give,
&want,
maximal,
);
if let Ok(received) = exchange_result {
self.holding.subsume_assets(received.into());
Ok(())
} else {
Err(XcmError::NoDeal)
}
})();
if result.is_err() {
self.holding = old_holding;
},
SetFeesMode { jit_withdraw } => {
self.fees_mode = FeesMode { jit_withdraw };
Ok(())
},
SetTopic(topic) => {
self.context.topic = Some(topic);
Ok(())
},
ClearTopic => {
self.context.topic = None;
Ok(())
},
AliasOrigin(target) => {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
if Config::Aliasers::contains(origin, &target) {
self.context.origin = Some(target);
Ok(())
} else {
Err(XcmError::NoPermission)
}
},
UnpaidExecution { check_origin, .. } => {
ensure!(
check_origin.is_none() || self.context.origin == check_origin,
XcmError::BadOrigin
);
Ok(())
Gavin Wood
committed
HrmpNewChannelOpenRequest { .. } => Err(XcmError::Unimplemented),
HrmpChannelAccepted { .. } => Err(XcmError::Unimplemented),
HrmpChannelClosing { .. } => Err(XcmError::Unimplemented),
Gavin Wood
committed
}