git.delta.rocks / unique-network / refs/commits / f0ad1b02de6f

difftreelog

refac: incapsulate CollectionHandler into CollectionDispatch

Trubnikov Sergey2023-04-24parent: #361b516.patch.diff
in: master

13 files changed

modifiedpallets/balances-adapter/src/lib.rsdiffbeforeafterboth
3#![warn(missing_docs)]3#![warn(missing_docs)]
44
5extern 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};
910
10pub mod common;11pub mod common;
11pub mod erc;12pub mod erc;
1213
13pub 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 }
1819
19 /// 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}
2424
25impl<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.0
28 }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.0
31 }31 }
32}32}
33#[frame_support::pallet]33#[frame_support::pallet]
modifiedpallets/common/src/dispatch.rsdiffbeforeafterboth
34 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 handle
46 .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 {
7266
73/// 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;
70
75 /// 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 where
93 Self: Sized;
9694
97 /// 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>;
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
77 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;77 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;
78}78}
79
80impl CommonEvmHandler for () {
81 const CODE: &'static [u8] = &[];
82
83 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
84 None
85 }
86}
7987
80/// @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))]
modifiedpallets/structure/src/benchmarking.rsdiffbeforeafterboth
42 },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();
4747
48 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)?;
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
155 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 config
158 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();
164163
165 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 };
407
408 let handle = <CollectionHandle<T>>::try_get(collection)?;
409405
410 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();
412408
413 action(dispatch, token)409 action(dispatch, token)
modifiedruntime/common/dispatch.rsdiffbeforeafterboth
59 + pallet_refungible::Config60 + pallet_refungible::Config
60 + 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 }
71
62 fn create(72 fn create(
63 sender: T::CrossAccountId,73 sender: T::CrossAccountId,
104 Ok(())114 Ok(())
105 }115 }
106116
107 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 }
121
122 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 }
120129
121 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 )?;
178191
179 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(),
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
17#[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();
2222
23 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)23 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
33 '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);
modifiedtests/src/eth/nativeFungible.test.tsdiffbeforeafterboth
29 });29 });
30 });30 });
3131
32 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);
modifiedtests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth
49 value: OptionUint,49 value: OptionUint,
50}50}
5151
52export const NON_EXISTENT_COLLECTION_ID = 4_294_967_295;
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
19// Pallets that must always be present19// Pallets that must always be present
20const requiredPallets = [20const requiredPallets = [
21 'balances',21 'balances',
22 'balancesadapter',
22 'common',23 'common',
23 'timestamp',24 'timestamp',
24 'transactionpayment',25 'transactionpayment',
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
17import {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';
2021
21describe('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;
124125
125126
126 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 });
131131
132 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 });
137136
138 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 });
143141
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
1616
17import {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';
1920
20describe('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 });
9899
99 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