Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OnAssetCreated and OnAssetDestroyed hook #32

Merged
merged 3 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions pallets/foreign-asset-creator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,35 @@ pub mod mock;
#[cfg(test)]
pub mod tests;

/// Trait for the OnForeignAssetRegistered hook
pub trait ForeignAssetCreatedHook<ForeignAsset, AssetId, AssetBalance> {
ParthDesai marked this conversation as resolved.
Show resolved Hide resolved
fn on_asset_created(
foreign_asset: &ForeignAsset,
asset_id: &AssetId,
min_balance: &AssetBalance,
);
}

impl<ForeignAsset, AssetId, AssetBalance>
ForeignAssetCreatedHook<ForeignAsset, AssetId, AssetBalance> for ()
{
fn on_asset_created(
_foreign_asset: &ForeignAsset,
_asset_id: &AssetId,
_min_balance: &AssetBalance,
) {
}
}

/// Trait for the OnForeignAssetDeregistered hook
pub trait ForeignAssetDestroyedHook<ForeignAsset, AssetId> {
fn on_asset_destroyed(foreign_asset: &ForeignAsset, asset_id: &AssetId);
}

impl<ForeignAsset, AssetId> ForeignAssetDestroyedHook<ForeignAsset, AssetId> for () {
fn on_asset_destroyed(_foreign_asset: &ForeignAsset, _asset_id: &AssetId) {}
}

#[pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -66,6 +95,16 @@ pub mod pallet {

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;

/// Hook to be called when new foreign asset is registered.
type OnForeignAssetCreated: ForeignAssetCreatedHook<
Self::ForeignAsset,
AssetId<Self>,
AssetBalance<Self>,
>;

/// Hook to be called when foreign asset is de-registered.
type OnForeignAssetDestroyed: ForeignAssetDestroyedHook<Self::ForeignAsset, AssetId<Self>>;
}

pub type AssetBalance<T> = <<T as Config>::Fungibles as fungibles::Inspect<
Expand Down Expand Up @@ -152,6 +191,8 @@ pub mod pallet {
AssetIdToForeignAsset::<T>::insert(&asset_id, &foreign_asset);
ForeignAssetToAssetId::<T>::insert(&foreign_asset, &asset_id);

T::OnForeignAssetCreated::on_asset_created(&foreign_asset, &asset_id, &min_balance);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see a reason why we would need the min_balance here, I guess we can leave it out for now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to make it general purpose. If particular kind of hook does not require min_balance, it can just ignore, I guess.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can make that more generic in the future if we would like, but I guess it's ok if we leave it as well


Self::deposit_event(Event::ForeignAssetCreated {
asset_id,
foreign_asset,
Expand Down Expand Up @@ -233,6 +274,8 @@ pub mod pallet {
// Remove from ForeignAssetToAssetId
ForeignAssetToAssetId::<T>::remove(&foreign_asset);

T::OnForeignAssetDestroyed::on_asset_destroyed(&foreign_asset, &asset_id);

Self::deposit_event(Event::ForeignAssetDestroyed {
asset_id,
foreign_asset,
Expand Down
77 changes: 76 additions & 1 deletion pallets/foreign-asset-creator/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

use super::*;
use crate as pallet_foreign_asset_creator;
use std::marker::PhantomData;

use frame_support::{
construct_runtime, parameter_types,
construct_runtime, parameter_types, storage,
traits::{ConstU32, Everything},
};
use frame_system::EnsureRoot;
use parity_scale_codec::{Decode, Encode};
use sp_core::H256;
use sp_runtime::traits::{BlakeTwo256, IdentityLookup};
use sp_runtime::BuildStorage;
Expand Down Expand Up @@ -126,6 +128,77 @@ impl pallet_assets::Config for Test {
}
}

/// Gets parameters of last `ForeignAssetCreatedHook::on_asset_created` hook invocation
pub fn get_asset_created_hook_invocation<
ForeignAsset: Decode,
AssetId: Decode,
AssetBalance: Decode,
>() -> Option<(ForeignAsset, AssetId, AssetBalance)> {
storage::unhashed::get_raw(b"____on_foreign_asset_created")
.map(|output| Decode::decode(&mut output.as_slice()).expect("Decoding should work"))
}

/// Notes down parameters of current `ForeignAssetCreatedHook::on_asset_created` hook invocation
fn note_on_asset_created_hook_invocation<
ForeignAsset: Encode,
AssetId: Encode,
AssetBalance: Encode,
>(
foreign_asset: &ForeignAsset,
asset_id: &AssetId,
min_balance: &AssetBalance,
) {
storage::unhashed::put_raw(
b"____on_foreign_asset_created",
(foreign_asset, asset_id, min_balance).encode().as_slice(),
);
}

/// Gets parameters of last `ForeignAssetDestroyedHook::on_asset_destroyed` hook invocation
pub fn get_asset_destroyed_hook_invocation<ForeignAsset: Decode, AssetId: Decode>(
) -> Option<(ForeignAsset, AssetId)> {
storage::unhashed::get_raw(b"____on_foreign_asset_destroyed")
.map(|output| Decode::decode(&mut output.as_slice()).expect("Decoding should work"))
}

/// Notes down parameters of current `ForeignAssetDestroyedHook::on_asset_destroyed` hook invocation
fn note_on_asset_destroyed_hook_invocation<ForeignAsset: Encode, AssetId: Encode>(
foreign_asset: &ForeignAsset,
asset_id: &AssetId,
) {
storage::unhashed::put_raw(
b"____on_foreign_asset_destroyed",
(foreign_asset, asset_id).encode().as_slice(),
);
}

/// Test hook that records the hook invocation with exact params
pub struct NoteDownHook<ForeignAsset, AssetId, AssetBalance>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

PhantomData<(ForeignAsset, AssetId, AssetBalance)>,
);

impl<ForeignAsset: Encode, AssetId: Encode, AssetBalance: Encode>
ForeignAssetCreatedHook<ForeignAsset, AssetId, AssetBalance>
for NoteDownHook<ForeignAsset, AssetId, AssetBalance>
{
fn on_asset_created(
foreign_asset: &ForeignAsset,
asset_id: &AssetId,
min_balance: &AssetBalance,
) {
note_on_asset_created_hook_invocation(foreign_asset, asset_id, min_balance);
}
}

impl<ForeignAsset: Encode, AssetId: Encode, AssetBalance>
ForeignAssetDestroyedHook<ForeignAsset, AssetId>
for NoteDownHook<ForeignAsset, AssetId, AssetBalance>
{
fn on_asset_destroyed(foreign_asset: &ForeignAsset, asset_id: &AssetId) {
note_on_asset_destroyed_hook_invocation(foreign_asset, asset_id);
}
}

impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type ForeignAsset = Location;
Expand All @@ -134,6 +207,8 @@ impl Config for Test {
type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
type Fungibles = Assets;
type WeightInfo = ();
type OnForeignAssetCreated = NoteDownHook<Location, AssetId, Balance>;
type OnForeignAssetDestroyed = NoteDownHook<Location, AssetId, Balance>;
}

pub(crate) struct ExtBuilder {
Expand Down
23 changes: 21 additions & 2 deletions pallets/foreign-asset-creator/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ fn creating_foreign_works() {
expect_events(vec![crate::Event::ForeignAssetCreated {
asset_id: 1,
foreign_asset: Location::parent(),
}])
}]);

let (foreign_asset, asset_id, min_balance): (Location, u32, u64) =
get_asset_created_hook_invocation()
.expect("Decoding of invocation data should not fail");
assert_eq!(foreign_asset, Location::parent());
assert_eq!(asset_id, 1u32);
assert_eq!(min_balance, 1u64);
});
}

Expand Down Expand Up @@ -205,6 +212,13 @@ fn test_destroy_foreign_asset_also_removes_everything() {
1u64,
));

let (foreign_asset, asset_id, min_balance): (Location, u32, u64) =
get_asset_created_hook_invocation()
.expect("Decoding of invocation data should not fail");
assert_eq!(foreign_asset, Location::parent());
assert_eq!(asset_id, 1u32);
assert_eq!(min_balance, 1u64);

assert_ok!(ForeignAssetCreator::destroy_foreign_asset(
RuntimeOrigin::root(),
1
Expand All @@ -223,6 +237,11 @@ fn test_destroy_foreign_asset_also_removes_everything() {
asset_id: 1,
foreign_asset: Location::parent(),
},
])
]);

let (foreign_asset, asset_id): (Location, u32) = get_asset_destroyed_hook_invocation()
.expect("Decoding of invocation data should not fail");
assert_eq!(foreign_asset, Location::parent());
assert_eq!(asset_id, 1u32);
});
}
Loading