In general you cannot prevent the state from being rolled back on an error.
Did you have a look at the pallet-utility
pallet?
The force_batch
call has a similar semantic where errors are reported through events. It does not abort on an error but rather emits them as events. The respective event definitions look like this:
/// A single item within a Batch of dispatches has completed with no error.
ItemCompleted,
/// A single item within a Batch of dispatches has completed with error.
ItemFailed { error: DispatchError },
It then emits these events depending on the result of a previous dispatch:
if let Err(e) = result {
Self::deposit_event(Event::ItemFailed { error: e.error });
} else {
Self::deposit_event(Event::ItemCompleted);
}
So you could probably define similar events for FreeCallConsumed
and ChildCallFailed
.