difftreelog
refac: incapsulate CollectionHandler into CollectionDispatch
in: master
13 files changed
pallets/balances-adapter/src/lib.rsdiffbeforeafterboth3#![warn(missing_docs)]3#![warn(missing_docs)]445extern crate alloc;5extern crate alloc;6use frame_support::sp_runtime::DispatchResult;6pub use pallet::*;7pub use pallet::*;7use pallet_common::CollectionHandle;8use pallet_common::CollectionHandle;8use pallet_evm_coder_substrate::{WithRecorder, SubstrateRecorder};9use pallet_evm_coder_substrate::{WithRecorder, SubstrateRecorder};91010pub mod common;11pub mod common;11pub mod erc;12pub mod erc;121313pub struct NativeFungibleHandle<T: Config>(CollectionHandle<T>);14pub struct NativeFungibleHandle<T: Config>(SubstrateRecorder<T>);14impl<T: Config> NativeFungibleHandle<T> {15impl<T: Config> NativeFungibleHandle<T> {15 pub fn cast(inner: CollectionHandle<T>) -> Self {16 pub fn new() -> NativeFungibleHandle<T> {16 Self(inner)17 Self(SubstrateRecorder::new(u64::MAX))17 }18 }181919 /// Casts [`NativeFungibleHandle`] into [`CollectionHandle`][`pallet_common::CollectionHandle`].20 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {20 pub fn check_is_internal(&self) -> DispatchResult {21 self.021 Ok(())22 }22 }23}23}242425impl<T: Config> WithRecorder<T> for NativeFungibleHandle<T> {25impl<T: Config> WithRecorder<T> for NativeFungibleHandle<T> {26 fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {26 fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {27 &self.0.recorder27 &self.028 }28 }29 fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {29 fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {30 self.0.recorder30 self.031 }31 }32}32}33#[frame_support::pallet]33#[frame_support::pallet]pallets/common/src/dispatch.rsdiffbeforeafterboth34 collection: CollectionId,34 collection: CollectionId,35 call: C,35 call: C,36) -> DispatchResultWithPostInfo {36) -> DispatchResultWithPostInfo {37 let handle =37 let dispatched = T::CollectionDispatch::dispatch(collection)38 .and_then(|dispatched| {39 dispatched.check_is_internal()?;40 Ok(dispatched)41 })38 CollectionHandle::try_get(collection).map_err(|error| DispatchErrorWithPostInfo {42 .map_err(|error| DispatchErrorWithPostInfo {39 post_info: PostDispatchInfo {43 post_info: PostDispatchInfo {40 actual_weight: Some(dispatch_weight::<T>()),44 actual_weight: Some(dispatch_weight::<T>()),41 pays_fee: Pays::Yes,45 pays_fee: Pays::Yes,42 },46 },43 error,47 error,44 })?;48 })?;45 handle46 .check_is_internal()47 .map_err(|error| DispatchErrorWithPostInfo {48 post_info: PostDispatchInfo {49 actual_weight: Some(dispatch_weight::<T>()),50 pays_fee: Pays::Yes,51 },52 error,53 })?;54 let dispatched = T::CollectionDispatch::dispatch(handle);55 let mut result = call(dispatched.as_dyn());49 let mut result = call(dispatched.as_dyn());56 match &mut result {50 match &mut result {57 Ok(PostDispatchInfo {51 Ok(PostDispatchInfo {726673/// Interface for working with different collections through the dispatcher.67/// Interface for working with different collections through the dispatcher.74pub trait CollectionDispatch<T: Config> {68pub trait CollectionDispatch<T: Config> {69 fn check_is_internal(&self) -> DispatchResult;7075 /// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode).71 /// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode).76 ///72 ///92 /// Get a specialized collection from the handle.88 /// Get a specialized collection from the handle.93 ///89 ///94 /// * `handle` - Collection handle.90 /// * `handle` - Collection handle.95 fn dispatch(handle: CollectionHandle<T>) -> Self;91 fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError>92 where93 Self: Sized;969497 /// Get the implementation of [`CommonCollectionOperations`].95 /// Get the implementation of [`CommonCollectionOperations`].98 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;96 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;pallets/common/src/erc.rsdiffbeforeafterboth77 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;77 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;78}78}7980impl CommonEvmHandler for () {81 const CODE: &'static [u8] = &[];8283 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {84 None85 }86}798780/// @title A contract that allows you to work with collections.88/// @title A contract that allows you to work with collections.81#[solidity_interface(name = Collection, enum(derive(PreDispatch)), enum_attr(weight))]89#[solidity_interface(name = Collection, enum(derive(PreDispatch)), enum_attr(weight))]pallets/structure/src/benchmarking.rsdiffbeforeafterboth42 },42 },43 CollectionFlags::default(),43 CollectionFlags::default(),44 )?;44 )?;45 let dispatch = T::CollectionDispatch::dispatch(CollectionHandle::try_get(CollectionId(1))?);45 let dispatch = T::CollectionDispatch::dispatch(CollectionId(1))?;46 let dispatch = dispatch.as_dyn();46 let dispatch = dispatch.as_dyn();474748 dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()), &Unlimited)?;48 dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()), &Unlimited)?;pallets/structure/src/lib.rsdiffbeforeafterboth155 token: TokenId,155 token: TokenId,156 ) -> Result<Parent<T::CrossAccountId>, DispatchError> {156 ) -> Result<Parent<T::CrossAccountId>, DispatchError> {157 // TODO: Reduce cost by not reading collection config157 // TODO: Reduce cost by not reading collection config158 let handle = match CollectionHandle::try_get(collection) {158 let handle = match T::CollectionDispatch::dispatch(collection) {159 Ok(v) => v,159 Ok(v) => v,160 Err(_) => return Ok(Parent::TokenNotFound),160 Err(_) => return Ok(Parent::TokenNotFound),161 };161 };162 let handle = T::CollectionDispatch::dispatch(handle);163 let handle = handle.as_dyn();162 let handle = handle.as_dyn();164163165 Ok(match handle.token_owner(token) {164 Ok(match handle.token_owner(token) {279 self_budget: &dyn Budget,278 self_budget: &dyn Budget,280 breadth_budget: &dyn Budget,279 breadth_budget: &dyn Budget,281 ) -> DispatchResultWithPostInfo {280 ) -> DispatchResultWithPostInfo {282 let handle = <CollectionHandle<T>>::try_get(collection)?;283 let dispatch = T::CollectionDispatch::dispatch(handle);281 let dispatch = T::CollectionDispatch::dispatch(collection)?;284 let dispatch = dispatch.as_dyn();282 let dispatch = dispatch.as_dyn();285 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)283 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)286 }284 }405 return Ok(())403 return Ok(())406 };404 };407408 let handle = <CollectionHandle<T>>::try_get(collection)?;409405410 let dispatch = T::CollectionDispatch::dispatch(handle);406 let dispatch = T::CollectionDispatch::dispatch(collection)?;411 let dispatch = dispatch.as_dyn();407 let dispatch = dispatch.as_dyn();412408413 action(dispatch, token)409 action(dispatch, token)runtime/common/dispatch.rsdiffbeforeafterboth59 + pallet_refungible::Config60 + pallet_refungible::Config60 + pallet_balances_adapter::Config,61 + pallet_balances_adapter::Config,61{62{63 fn check_is_internal(&self) -> DispatchResult {64 match self {65 Self::Fungible(h) => h.check_is_internal(),66 Self::Nonfungible(h) => h.check_is_internal(),67 Self::Refungible(h) => h.check_is_internal(),68 Self::NativeFungible(h) => h.check_is_internal(),69 }70 }7162 fn create(72 fn create(63 sender: T::CrossAccountId,73 sender: T::CrossAccountId,104 Ok(())114 Ok(())105 }115 }106116107 fn dispatch(handle: CollectionHandle<T>) -> Self {117 fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError> {118 if collection_id == CollectionId(0) {119 return Ok(Self::NativeFungible(NativeFungibleHandle::new()));120 }121122 let handle = <CollectionHandle<T>>::try_get(collection_id)?;108 match handle.mode {123 Ok(match handle.mode {109 CollectionMode::Fungible(_) => {124 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),110 if handle.id != up_data_structs::CollectionId(0) {111 Self::Fungible(FungibleHandle::cast(handle))112 } else {113 Self::NativeFungible(NativeFungibleHandle::cast(handle))114 }115 }116 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),125 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),117 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),126 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),118 }127 })119 }128 }120129121 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {130 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {122 match self {131 match self {172 }181 }173 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {182 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {174 if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {183 if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {184 if collection_id == CollectionId(0) {185 <NativeFungibleHandle<T>>::new().call(handle)186 } else {175 let collection =187 let collection = <CollectionHandle<T>>::new_with_gas_limit(176 <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;188 collection_id,177 let dispatched = Self::dispatch(collection);189 handle.remaining_gas(),190 )?;178191179 match dispatched {192 match collection.mode {180 Self::Fungible(h) => h.call(handle),193 CollectionMode::Fungible(_) => FungibleHandle::cast(collection).call(handle),181 Self::Nonfungible(h) => h.call(handle),194 CollectionMode::NFT => NonfungibleHandle::cast(collection).call(handle),182 Self::Refungible(h) => h.call(handle),195 CollectionMode::ReFungible => RefungibleHandle::cast(collection).call(handle),183 Self::NativeFungible(h) => h.call(handle),184 }196 }197 }185 } else if let Some((collection_id, token_id)) =198 } else if let Some((collection_id, token_id)) =186 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(199 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(187 &handle.code_address(),200 &handle.code_address(),runtime/common/runtime_apis.rsdiffbeforeafterboth17#[macro_export]17#[macro_export]18macro_rules! dispatch_unique_runtime {18macro_rules! dispatch_unique_runtime {19 ($collection:ident.$method:ident($($name:ident),*) $($rest:tt)*) => {{19 ($collection:ident.$method:ident($($name:ident),*) $($rest:tt)*) => {{20 let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);20 let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch($collection)?;21 let dispatch = collection.as_dyn();21 let dispatch = collection.as_dyn();222223 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)23 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)tests/src/eth/fungible.test.tsdiffbeforeafterboth33 'substrate' as const,33 'substrate' as const,34 'ethereum' as const,34 'ethereum' as const,35 ].map(testCase => {35 ].map(testCase => {36 itEth.only(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {36 itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {37 // 1. Create receiver depending on the test case:37 // 1. Create receiver depending on the test case:38 const receiverEth = helper.eth.createAccount();38 const receiverEth = helper.eth.createAccount();39 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);39 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);tests/src/eth/nativeFungible.test.tsdiffbeforeafterboth29 });29 });30 });30 });313132 itEth.only('Can perform approve()', async ({helper}) => {32 itEth.skip('Can perform approve()', async ({helper}) => {33 const owner = await helper.eth.createAccountWithBalance(donor);33 const owner = await helper.eth.createAccountWithBalance(donor);34 const spender = helper.eth.createAccount();34 const spender = helper.eth.createAccount();35 const collection = await helper.ft.mintCollection(alice);35 const collection = await helper.ft.mintCollection(alice);tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth49 value: OptionUint,49 value: OptionUint,50}50}515152export const NON_EXISTENT_COLLECTION_ID = 4_294_967_295;tests/src/pallet-presence.test.tsdiffbeforeafterboth19// Pallets that must always be present19// Pallets that must always be present20const requiredPallets = [20const requiredPallets = [21 'balances',21 'balances',22 'balancesadapter',22 'common',23 'common',23 'timestamp',24 'timestamp',24 'transactionpayment',25 'transactionpayment',tests/src/transfer.test.tsdiffbeforeafterboth17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {itEth, usingEthPlaygrounds} from './eth/util';18import {itEth, usingEthPlaygrounds} from './eth/util';19import {itSub, Pallets, usingPlaygrounds, expect} from './util';19import {itSub, Pallets, usingPlaygrounds, expect} from './util';20import {NON_EXISTENT_COLLECTION_ID} from './eth/util/playgrounds/types';202121describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {22describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {22 let donor: IKeyringPair;23 let donor: IKeyringPair;124125125126126 itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {127 itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {127 const collectionId = (1 << 32) - 1;128 await expect(helper.nft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))128 await expect(helper.nft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))129 .to.be.rejectedWith(/common\.CollectionNotFound/);129 .to.be.rejectedWith(/common\.CollectionNotFound/);130 });130 });131131132 itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {132 itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {133 const collectionId = (1 << 32) - 1;134 await expect(helper.ft.transfer(alice, collectionId, {Substrate: bob.address}))133 await expect(helper.ft.transfer(alice, NON_EXISTENT_COLLECTION_ID, {Substrate: bob.address}))135 .to.be.rejectedWith(/common\.CollectionNotFound/);134 .to.be.rejectedWith(/common\.CollectionNotFound/);136 });135 });137136138 itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {137 itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {139 const collectionId = (1 << 32) - 1;140 await expect(helper.rft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))138 await expect(helper.rft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))141 .to.be.rejectedWith(/common\.CollectionNotFound/);139 .to.be.rejectedWith(/common\.CollectionNotFound/);142 });140 });143141tests/src/transferFrom.test.tsdiffbeforeafterboth161617import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {itSub, Pallets, usingPlaygrounds, expect} from './util';18import {itSub, Pallets, usingPlaygrounds, expect} from './util';19import {NON_EXISTENT_COLLECTION_ID} from './eth/util/playgrounds/types';192020describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {21describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {21 let alice: IKeyringPair;22 let alice: IKeyringPair;97 });98 });989999 itSub('transferFrom for a collection that does not exist', async ({helper}) => {100 itSub('transferFrom for a collection that does not exist', async ({helper}) => {100 const collectionId = (1 << 32) - 1;101 await expect(helper.collection.approveToken(alice, collectionId, 0, {Substrate: bob.address}, 1n))101 await expect(helper.collection.approveToken(alice, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: bob.address}, 1n))102 .to.be.rejectedWith(/common\.CollectionNotFound/);102 .to.be.rejectedWith(/common\.CollectionNotFound/);103 await expect(helper.collection.transferTokenFrom(bob, collectionId, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))103 await expect(helper.collection.transferTokenFrom(bob, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))104 .to.be.rejectedWith(/common\.CollectionNotFound/);104 .to.be.rejectedWith(/common\.CollectionNotFound/);105 });105 });106106