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

difftreelog

CORE-345 Split evm collection to collection and helper

Trubnikov Sergey2022-05-18parent: #2cfa7af.patch.diff
in: master

16 files changed

modifiedMakefilediffbeforeafterboth
18COLLECTION_STUBS=./pallets/unique/src/eth/stubs/18COLLECTION_STUBS=./pallets/unique/src/eth/stubs/
19COLLECTION_ABI=./tests/src/eth/collectionAbi.json19COLLECTION_ABI=./tests/src/eth/collectionAbi.json
20
21COLLECTION_HELPER_STUBS=$(COLLECTION_STUBS)
22COLLECTION_HELPER_ABI=./tests/src/eth/collectionHelperAbi.json
2023
21TESTS_API=./tests/src/eth/api/24TESTS_API=./tests/src/eth/api/
2225
36 PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh39 PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
3740
38Collection.sol:41Collection.sol:
39 PACKAGE=pallet-unique NAME=eth::pallet_evm_collection::collection_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh42 PACKAGE=pallet-unique NAME=eth::evm_collection::collection_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
40 PACKAGE=pallet-unique NAME=eth::pallet_evm_collection::collection_impl OUTPUT=$(COLLECTION_STUBS)/$@ ./.maintain/scripts/generate_sol.sh43 PACKAGE=pallet-unique NAME=eth::evm_collection::collection_impl OUTPUT=$(COLLECTION_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
44
45CollectionHelper.sol:
46 PACKAGE=pallet-unique NAME=eth::evm_collection::collection_helper_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
47 PACKAGE=pallet-unique NAME=eth::evm_collection::collection_helper_impl OUTPUT=$(COLLECTION_HELPER_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
4148
42UniqueFungible: UniqueFungible.sol49UniqueFungible: UniqueFungible.sol
43 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh50 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh
55 INPUT=$(COLLECTION_STUBS)/$< OUTPUT=$(COLLECTION_STUBS)/Collection.raw ./.maintain/scripts/compile_stub.sh62 INPUT=$(COLLECTION_STUBS)/$< OUTPUT=$(COLLECTION_STUBS)/Collection.raw ./.maintain/scripts/compile_stub.sh
56 INPUT=$(COLLECTION_STUBS)/$< OUTPUT=$(COLLECTION_ABI) ./.maintain/scripts/generate_abi.sh63 INPUT=$(COLLECTION_STUBS)/$< OUTPUT=$(COLLECTION_ABI) ./.maintain/scripts/generate_abi.sh
64
65CollectionHelper: CollectionHelper.sol
66 INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelper.raw ./.maintain/scripts/compile_stub.sh
67 INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh
5768
58evm_stubs: UniqueFungible UniqueNFT ContractHelpers Collection69evm_stubs: UniqueFungible UniqueNFT ContractHelpers Collection CollectionHelper
5970
60.PHONY: _bench71.PHONY: _bench
61_bench:72_bench:
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
112 use sp_std::{vec::Vec, rc::Rc};112 use sp_std::{vec::Vec, rc::Rc};
113 use alloc::format;113 use alloc::format;
114 114
115 // #[pallet::config]
116 pub trait Config:115 pub trait Config:
117 frame_system::Config116 frame_system::Config
118 + pallet_evm_coder_substrate::Config117 + pallet_evm_coder_substrate::Config
122 type ContractAddress: Get<H160>;121 type ContractAddress: Get<H160>;
123 }122 }
124123
124 struct EvmCollectionHelper<T: Config>(Rc<SubstrateRecorder<T>>);
125 impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {
126 fn recorder(&self) -> &SubstrateRecorder<T> {
127 &self.0
128 }
129
130 fn into_recorder(self) -> Rc<SubstrateRecorder<T>> {
131 self.0
132 }
133 }
134
135 #[solidity_interface(name = "CollectionHelper")]
136 impl<T: Config> EvmCollectionHelper<T> {
137 fn create_721_collection(
138 &self,
139 caller: caller,
140 name: string,
141 description: string,
142 token_prefix: string,
143 ) -> Result<address> {
144 let caller = T::CrossAccountId::from_eth(caller);
145 let name = name
146 .encode_utf16()
147 .collect::<Vec<u16>>()
148 .try_into()
149 .map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;
150 let description = description
151 .encode_utf16()
152 .collect::<Vec<u16>>()
153 .try_into()
154 .map_err(|_| {
155 error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)
156 })?;
157 let token_prefix = token_prefix
158 .into_bytes()
159 .try_into()
160 .map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;
161
162 let data = CreateCollectionData {
163 name,
164 description,
165 token_prefix,
166 ..Default::default()
167 };
168
169 let collection_id =
170 <pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)
171 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
172
173 let address = pallet_common::eth::collection_id_to_address(collection_id);
174 self.0.log_mirrored(EthCollectionEvent::CollectionCreated {
175 owner: *caller.as_eth(),
176 collection_id: address,
177 });
178 Ok(address)
179 }
180 }
181
125 struct EvmCollection<T: Config>(Rc<SubstrateRecorder<T>>);182 struct EvmCollection<T: Config>(Rc<SubstrateRecorder<T>>);
126 impl<T: Config> WithRecorder<T> for EvmCollection<T> {183 impl<T: Config> WithRecorder<T> for EvmCollection<T> {
145 202
146 #[solidity_interface(name = "Collection")]203 #[solidity_interface(name = "Collection")]
147 impl<T: Config> EvmCollection<T> {204 impl<T: Config> EvmCollection<T> {
148 fn create_721_collection(
149 &self,
150 caller: caller,
151 name: string,
152 description: string,
153 token_prefix: string,
154 ) -> Result<address> {
155 let caller = T::CrossAccountId::from_eth(caller);
156 let name = name
157 .encode_utf16()
158 .collect::<Vec<u16>>()
159 .try_into()
160 .map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;
161 let description = description
162 .encode_utf16()
163 .collect::<Vec<u16>>()
164 .try_into()
165 .map_err(|_| {
166 error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)
167 })?;
168 let token_prefix = token_prefix
169 .into_bytes()
170 .try_into()
171 .map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;
172
173 let data = CreateCollectionData {
174 name,
175 description,
176 token_prefix,
177 ..Default::default()
178 };
179
180 let collection_id =
181 <pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)
182 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
183
184 let address = pallet_common::eth::collection_id_to_address(collection_id);
185 self.0.log_mirrored(EthCollectionEvent::CollectionCreated {
186 owner: *caller.as_eth(),
187 collection_id: address,
188 });
189 Ok(address)
190 }
191
192 fn set_sponsor(205 fn set_sponsor(
193 &self,206 &self,
194 caller: caller,207 caller: caller,
195 collection_address: address,
196 sponsor: address,208 sponsor: address,
197 ) -> Result<void> {209 ) -> Result<void> {
198 let mut collection = collection_from_address(collection_address, &self.0)?;210 let mut collection = collection_from_address(self.contract_address(caller).unwrap(), &self.0)?;
199 check_is_owner(caller, &collection)?;211 check_is_owner(caller, &collection)?;
200 212
201 let sponsor = T::CrossAccountId::from_eth(sponsor);213 let sponsor = T::CrossAccountId::from_eth(sponsor);
202 collection.set_sponsor(sponsor.as_sub().clone());214 collection.set_sponsor(sponsor.as_sub().clone());
203 save_eth(collection)215 save_eth(collection)
204 }216 }
205 217
206 fn confirm_sponsorship(&self, caller: caller, collection_address: address) -> Result<void> {218 fn confirm_sponsorship(&self, caller: caller) -> Result<void> {
207 let mut collection = collection_from_address(collection_address, &self.0)?;219 let mut collection = collection_from_address(self.contract_address(caller).unwrap(), &self.0)?;
208 let caller = T::CrossAccountId::from_eth(caller);220 let caller = T::CrossAccountId::from_eth(caller);
209 if !collection.confirm_sponsorship(caller.as_sub()) {221 if !collection.confirm_sponsorship(caller.as_sub()) {
210 return Err(Error::Revert("Caller is not set as sponsor".into()));222 return Err(Error::Revert("Caller is not set as sponsor".into()));
215 fn set_limits(227 fn set_limits(
216 &self,228 &self,
217 caller: caller,229 caller: caller,
218 collection_address: address,
219 limits_json: string,230 limits_json: string,
220 ) -> Result<void> {231 ) -> Result<void> {
221 let mut collection = collection_from_address(collection_address, &self.0)?;232 let mut collection = collection_from_address(self.contract_address(caller).unwrap(), &self.0)?;
222 check_is_owner(caller, &collection)?;233 check_is_owner(caller, &collection)?;
223 234
224 let limits = serde_json_core::from_str(limits_json.as_ref())235 let limits = serde_json_core::from_str(limits_json.as_ref())
227 save_eth(collection)238 save_eth(collection)
228 }239 }
240
241 fn contract_address(&self, _caller: caller) -> Result<address> {
242 Ok(self.0.contract())
243 }
229 }244 }
230 245
231 fn error_feild_too_long(feild: &str, bound: u32) -> Error {246 fn error_feild_too_long(feild: &str, bound: u32) -> Error {
252 Ok(())267 Ok(())
253 }268 }
254 269
270 pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);
271 impl<T: Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {
272 fn is_reserved(contract: &sp_core::H160) -> bool {
273 contract == &T::ContractAddress::get()
274 }
275
276 fn is_used(contract: &sp_core::H160) -> bool {
277 contract == &T::ContractAddress::get()
278 }
279
280 fn call(
281 source: &sp_core::H160,
282 target: &sp_core::H160,
283 gas_left: u64,
284 input: &[u8],
285 value: sp_core::U256,
286 ) -> Option<PrecompileResult> {
287 if target != &T::ContractAddress::get() {
288 return None;
289 }
290
291 let helpers = EvmCollectionHelper::<T>(Rc::new(SubstrateRecorder::<T>::new(*target, gas_left)));
292 pallet_evm_coder_substrate::call(*source, helpers, value, input)
293 }
294
295 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {
296 (contract == &T::ContractAddress::get())
297 .then(|| include_bytes!("./stubs/CollectionHelper.raw").to_vec())
298 }
299 }
300
301 generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true);
302 generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false);
303
255 pub struct CollectionOnMethodCall<T: Config>(PhantomData<*const T>);304 pub struct CollectionOnMethodCall<T: Config>(PhantomData<*const T>);
256 impl<T: Config> OnMethodCall<T> for CollectionOnMethodCall<T> {305 impl<T: Config> OnMethodCall<T> for CollectionOnMethodCall<T> {
269 input: &[u8],318 input: &[u8],
270 value: sp_core::U256,319 value: sp_core::U256,
271 ) -> Option<PrecompileResult> {320 ) -> Option<PrecompileResult> {
272 if target != &T::ContractAddress::get() {
273 return None;
274 }
275
276 let helpers = EvmCollection::<T>(Rc::new(SubstrateRecorder::<T>::new(*target, gas_left)));321 let helpers = EvmCollection::<T>(Rc::new(SubstrateRecorder::<T>::new(*target, gas_left)));
277 pallet_evm_coder_substrate::call(*source, helpers, value, input)322 pallet_evm_coder_substrate::call(*source, helpers, value, input)
modifiedpallets/unique/src/eth/stubs/Collection.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/unique/src/eth/stubs/Collection.soldiffbeforeafterboth
21 }21 }
22}22}
2323
24// Selector: 1e95830f24// Selector: 15cc740e
25contract Collection is Dummy, ERC165 {25contract Collection is Dummy, ERC165 {
26 // Selector: create721Collection(string,string,string) 951c015126 // Selector: setSponsor(address) 59753fb1
27 function create721Collection(27 function setSponsor(address sponsor) public view {
28 string memory name,
29 string memory description,
30 string memory tokenPrefix
31 ) public view returns (address) {
32 require(false, stub_error);28 require(false, stub_error);
33 name;29 sponsor;
34 description;
35 tokenPrefix;
36 dummy;30 dummy;
37 return 0x0000000000000000000000000000000000000000;
38 }31 }
3932
40 // Selector: setSponsor(address,address) f01fba9333 // Selector: confirmSponsorship() c8c6a056
41 function setSponsor(address collectionAddress, address sponsor)34 function confirmSponsorship() public view {
42 public
43 view
44 {
45 require(false, stub_error);35 require(false, stub_error);
46 collectionAddress;
47 sponsor;
48 dummy;36 dummy;
49 }37 }
5038
51 // Selector: confirmSponsorship(address) abc0000139 // Selector: setLimits(string) 72cb345d
52 function confirmSponsorship(address collectionAddress) public view {40 function setLimits(string memory limitsJson) public view {
53 require(false, stub_error);41 require(false, stub_error);
54 collectionAddress;42 limitsJson;
55 dummy;43 dummy;
56 }44 }
5745
58 // Selector: setLimits(address,string) d05638cc46 // Selector: contractAddress() f6b4dfb4
59 function setLimits(address collectionAddress, string memory limitsJson)47 function contractAddress() public view returns (address) {
60 public
61 view
62 {
63 require(false, stub_error);48 require(false, stub_error);
64 collectionAddress;
65 limitsJson;
66 dummy;49 dummy;
50 return 0x0000000000000000000000000000000000000000;
67 }51 }
68}52}
6953
addedpallets/unique/src/eth/stubs/CollectionHelper.rawdiffbeforeafterboth

binary blob — no preview

addedpallets/unique/src/eth/stubs/CollectionHelper.soldiffbeforeafterboth

no changes

modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
308 pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,308 pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
309 CollectionDispatchT<Self>,309 CollectionDispatchT<Self>,
310 evm_collection::CollectionOnMethodCall<Self>,310 evm_collection::CollectionOnMethodCall<Self>,
311 evm_collection::CollectionHelperOnMethodCall<Self>,
311 );312 );
312 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;313 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
313 type ChainId = ChainId;314 type ChainId = ChainId;
978 ]);979 ]);
979980
980 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f981 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
981 pub const EvmCollectionAddress: H160 = H160([982 pub const EvmCollectionHelperAddress: H160 = H160([
982 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,983 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
983 ]);984 ]);
984}985}
989}990}
990991
991impl evm_collection::Config for Runtime {992impl evm_collection::Config for Runtime {
992 type ContractAddress = EvmCollectionAddress;993 type ContractAddress = EvmCollectionHelperAddress;
993}994}
994995
995construct_runtime!(996construct_runtime!(
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
280 pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,280 pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
281 CollectionDispatchT<Self>,281 CollectionDispatchT<Self>,
282 evm_collection::CollectionOnMethodCall<Self>,282 evm_collection::CollectionOnMethodCall<Self>,
283 evm_collection::CollectionHelperOnMethodCall<Self>,
283 );284 );
284 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;285 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
285 type ChainId = ChainId;286 type ChainId = ChainId;
955 ]);956 ]);
956 957
957 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f958 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
958 pub const EvmCollectionAddress: H160 = H160([959 pub const EvmCollectionHelperAddress: H160 = H160([
959 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,960 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
960 ]);961 ]);
961}962}
966}967}
967968
968impl evm_collection::Config for Runtime {969impl evm_collection::Config for Runtime {
969 type ContractAddress = EvmCollectionAddress;970 type ContractAddress = EvmCollectionHelperAddress;
970}971}
971972
972construct_runtime!(973construct_runtime!(
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
284 pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,284 pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
285 CollectionDispatchT<Self>,285 CollectionDispatchT<Self>,
286 evm_collection::CollectionOnMethodCall<Self>,286 evm_collection::CollectionOnMethodCall<Self>,
287 evm_collection::CollectionHelperOnMethodCall<Self>,
287 );288 );
288 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;289 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
289 type ChainId = ChainId;290 type ChainId = ChainId;
960 ]);961 ]);
961 962
962 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f963 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
963 pub const EvmCollectionAddress: H160 = H160([964 pub const EvmCollectionHelperAddress: H160 = H160([
964 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,965 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
965 ]);966 ]);
966}967}
971}972}
972973
973impl evm_collection::Config for Runtime {974impl evm_collection::Config for Runtime {
974 type ContractAddress = EvmCollectionAddress;975 type ContractAddress = EvmCollectionHelperAddress;
975}976}
976977
977construct_runtime!(978construct_runtime!(
modifiedtests/src/eth/api/Collection.soldiffbeforeafterboth
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}13}
1414
15// Selector: 1e95830f15// Selector: 15cc740e
16interface Collection is Dummy, ERC165 {16interface Collection is Dummy, ERC165 {
17 // Selector: create721Collection(string,string,string) 951c0151
18 function create721Collection(
19 string memory name,
20 string memory description,
21 string memory tokenPrefix
22 ) external view returns (address);
23
24 // Selector: setSponsor(address,address) f01fba9317 // Selector: setSponsor(address) 59753fb1
25 function setSponsor(address collectionAddress, address sponsor)18 function setSponsor(address sponsor) external view;
26 external
27 view;
2819
29 // Selector: confirmSponsorship(address) abc0000120 // Selector: confirmSponsorship() c8c6a056
30 function confirmSponsorship(address collectionAddress) external view;21 function confirmSponsorship() external view;
3122
32 // Selector: setLimits(address,string) d05638cc23 // Selector: setLimits(string) 72cb345d
33 function setLimits(address collectionAddress, string memory limitsJson)24 function setLimits(string memory limitsJson) external view;
34 external25
35 view;26 // Selector: contractAddress() f6b4dfb4
27 function contractAddress() external view returns (address);
36}28}
3729
addedtests/src/eth/api/CollectionHelper.soldiffbeforeafterboth

no changes

modifiedtests/src/eth/collectionAbi.jsondiffbeforeafterboth
1[1[
2 {2 {
3 "inputs": [3 "inputs": [],
4 {
5 "internalType": "address",
6 "name": "collectionAddress",
7 "type": "address"
8 }
9 ],
10 "name": "confirmSponsorship",4 "name": "confirmSponsorship",
11 "outputs": [],5 "outputs": [],
14 },8 },
15 {9 {
16 "inputs": [10 "inputs": [],
17 { "internalType": "string", "name": "name", "type": "string" },
18 { "internalType": "string", "name": "description", "type": "string" },
19 { "internalType": "string", "name": "tokenPrefix", "type": "string" }
20 ],
21 "name": "create721Collection",11 "name": "contractAddress",
22 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],12 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
23 "stateMutability": "view",13 "stateMutability": "view",
24 "type": "function"14 "type": "function"
25 },15 },
26 {16 {
27 "inputs": [17 "inputs": [
28 {
29 "internalType": "address",
30 "name": "collectionAddress",
31 "type": "address"
32 },
33 { "internalType": "string", "name": "limitsJson", "type": "string" }18 { "internalType": "string", "name": "limitsJson", "type": "string" }
34 ],19 ],
35 "name": "setLimits",20 "name": "setLimits",
39 },24 },
40 {25 {
41 "inputs": [26 "inputs": [
42 {
43 "internalType": "address",
44 "name": "collectionAddress",
45 "type": "address"
46 },
47 { "internalType": "address", "name": "sponsor", "type": "address" }27 { "internalType": "address", "name": "sponsor", "type": "address" }
48 ],28 ],
49 "name": "setSponsor",29 "name": "setSponsor",
addedtests/src/eth/collectionHelperAbi.jsondiffbeforeafterboth

no changes

modifiedtests/src/eth/createCollection.test.tsdiffbeforeafterboth
20import {expect} from 'chai';20import {expect} from 'chai';
21import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';21import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
22import {22import {
23 collectionHelper,23 evmCollectionHelper,
24 collectionIdFromAddress,24 collectionIdFromAddress,
25 collectionIdToAddress,25 collectionIdToAddress,
26 createEthAccount,26 createEthAccount,
27 createEthAccountWithBalance,27 createEthAccountWithBalance,
28 evmCollection,
28 GAS_ARGS,29 GAS_ARGS,
29 itWeb3,30 itWeb3,
30 normalizeAddress,31 normalizeAddress,
41describe('Create collection from EVM', () => {42describe('Create collection from EVM', () => {
42 itWeb3('Create collection', async ({api, web3}) => {43 itWeb3('Create collection', async ({api, web3}) => {
43 const owner = await createEthAccountWithBalance(api, web3);44 const owner = await createEthAccountWithBalance(api, web3);
44 const helper = collectionHelper(web3, owner);45 const helper = evmCollectionHelper(web3, owner);
45 const collectionName = 'CollectionEVM';46 const collectionName = 'CollectionEVM';
46 const description = 'Some description';47 const description = 'Some description';
47 const tokenPrefix = 'token prefix';48 const tokenPrefix = 'token prefix';
63 64
64 itWeb3('Set sponsorship', async ({api, web3}) => {65 itWeb3('Set sponsorship', async ({api, web3}) => {
65 const owner = await createEthAccountWithBalance(api, web3);66 const owner = await createEthAccountWithBalance(api, web3);
66 const helper = collectionHelper(web3, owner);67 const collectionHelper = evmCollectionHelper(web3, owner);
67 let result = await helper.methods.create721Collection('Sponsor collection', '1', '1').send();68 let result = await collectionHelper.methods.create721Collection('Sponsor collection', '1', '1').send();
68 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);69 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
69 const sponsor = await createEthAccountWithBalance(api, web3);70 const sponsor = await createEthAccountWithBalance(api, web3);
71 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
70 result = await helper.methods.setSponsor(collectionIdAddress, sponsor).send();72 result = await collectionEvm.methods.setSponsor(sponsor).send();
71 let collection = (await getDetailedCollectionInfo(api, collectionId))!;73 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
72 expect(collection.sponsorship.isUnconfirmed).to.be.true;74 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;
73 expect(collection.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));75 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
74 await expect(helper.methods.confirmSponsorship(collectionIdAddress).call()).to.be.rejectedWith('Caller is not set as sponsor');76 await expect(collectionEvm.methods.confirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
75 const sponsorHelper = collectionHelper(web3, sponsor);77 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
76 await sponsorHelper.methods.confirmSponsorship(collectionIdAddress).send();78 await sponsorCollection.methods.confirmSponsorship().send();
77 collection = (await getDetailedCollectionInfo(api, collectionId))!;79 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
78 expect(collection.sponsorship.isConfirmed).to.be.true;80 expect(collectionSub.sponsorship.isConfirmed).to.be.true;
79 expect(collection.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));81 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
80 });82 });
8183
82 itWeb3('Set limits', async ({api, web3}) => {84 itWeb3('Set limits', async ({api, web3}) => {
83 const owner = await createEthAccountWithBalance(api, web3);85 const owner = await createEthAccountWithBalance(api, web3);
84 const helper = collectionHelper(web3, owner);86 const collectionHelper = evmCollectionHelper(web3, owner);
85 const result = await helper.methods.create721Collection('Const collection', '5', '5').send();87 const result = await collectionHelper.methods.create721Collection('Const collection', '5', '5').send();
86 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);88 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
87 const limits = {89 const limits = {
88 accountTokenOwnershipLimit: 1000,90 accountTokenOwnershipLimit: 1000,
97 };99 };
98100
99 const limitsJson = JSON.stringify(limits, null, 1);101 const limitsJson = JSON.stringify(limits, null, 1);
102 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
100 await helper.methods.setLimits(collectionIdAddress, limitsJson).send();103 await collectionEvm.methods.setLimits(limitsJson).send();
101 104
102 const collection = (await getDetailedCollectionInfo(api, collectionId))!;105 const collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
103 expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit);106 expect(collectionSub.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit);
104 expect(collection.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize);107 expect(collectionSub.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize);
105 expect(collection.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit.Blocks);108 expect(collectionSub.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit.Blocks);
106 expect(collection.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit);109 expect(collectionSub.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit);
107 expect(collection.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout);110 expect(collectionSub.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout);
108 expect(collection.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout);111 expect(collectionSub.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout);
109 expect(collection.limits.ownerCanTransfer.toHuman()).to.be.eq(limits.ownerCanTransfer);112 expect(collectionSub.limits.ownerCanTransfer.toHuman()).to.be.eq(limits.ownerCanTransfer);
110 expect(collection.limits.ownerCanDestroy.toHuman()).to.be.eq(limits.ownerCanDestroy);113 expect(collectionSub.limits.ownerCanDestroy.toHuman()).to.be.eq(limits.ownerCanDestroy);
111 expect(collection.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled);114 expect(collectionSub.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled);
112 });115 });
113116
114 itWeb3('Check tokenURI', async ({web3, api}) => {117 itWeb3('Check tokenURI', async ({web3, api}) => {
115 const owner = await createEthAccountWithBalance(api, web3);118 const owner = await createEthAccountWithBalance(api, web3);
116 const helper = collectionHelper(web3, owner);119 const helper = evmCollectionHelper(web3, owner);
117 let result = await helper.methods.create721Collection('Mint collection', '6', '6').send();120 let result = await helper.methods.create721Collection('Mint collection', '6', '6').send();
118 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);121 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
119 const receiver = createEthAccount(web3);122 const receiver = createEthAccount(web3);
154describe('(!negative tests!) Create collection from EVM', () => {157describe('(!negative tests!) Create collection from EVM', () => {
155 itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3}) => {158 itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3}) => {
156 const owner = await createEthAccountWithBalance(api, web3);159 const owner = await createEthAccountWithBalance(api, web3);
157 const helper = collectionHelper(web3, owner);160 const helper = evmCollectionHelper(web3, owner);
158 {161 {
159 const MAX_NAME_LENGHT = 64;162 const MAX_NAME_LENGHT = 64;
160 const collectionName = 'A'.repeat(MAX_NAME_LENGHT + 1);163 const collectionName = 'A'.repeat(MAX_NAME_LENGHT + 1);
188 191
189 itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {192 itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {
190 const owner = await createEthAccount(web3);193 const owner = await createEthAccount(web3);
191 const helper = collectionHelper(web3, owner);194 const helper = evmCollectionHelper(web3, owner);
192 const collectionName = 'A';195 const collectionName = 'A';
193 const description = 'A';196 const description = 'A';
194 const tokenPrefix = 'A';197 const tokenPrefix = 'A';
200203
201 itWeb3('(!negative test!) Collection address (Contract is not an unique collection)', async ({api, web3}) => {204 itWeb3('(!negative test!) Collection address (Contract is not an unique collection)', async ({api, web3}) => {
202 const owner = await createEthAccountWithBalance(api, web3);205 const owner = await createEthAccountWithBalance(api, web3);
206 const collectionAddressWithBadPrefix = '0x00112233445566778899AABBCCDDEEFF00112233';
203 const helper = collectionHelper(web3, owner);207 const collectionEvm = evmCollection(web3, owner, collectionAddressWithBadPrefix);
204 const collectionAddressWithBadPrefix = '0x00112233445566778899AABBCCDDEEFF00112233';
205 const EXPECTED_ERROR = 'Contract is not an unique collection';208 const EXPECTED_ERROR = 'Contract is not an unique collection';
206 {209 {
207 const sponsor = await createEthAccountWithBalance(api, web3);210 const sponsor = await createEthAccountWithBalance(api, web3);
208 await expect(helper.methods211 await expect(collectionEvm.methods
209 .setSponsor(collectionAddressWithBadPrefix, sponsor)212 .setSponsor(sponsor)
210 .call()).to.be.rejectedWith(EXPECTED_ERROR);213 .call()).to.be.rejectedWith(EXPECTED_ERROR);
211 214
212 const sponsorHelper = collectionHelper(web3, sponsor);215 const sponsorCollection = evmCollection(web3, sponsor, collectionAddressWithBadPrefix);
213 await expect(sponsorHelper.methods216 await expect(sponsorCollection.methods
214 .confirmSponsorship(collectionAddressWithBadPrefix)217 .confirmSponsorship()
215 .call()).to.be.rejectedWith(EXPECTED_ERROR);218 .call()).to.be.rejectedWith(EXPECTED_ERROR);
216 }219 }
217 {220 {
218 const limits = '{"account_token_ownership_limit":1000}';221 const limits = '{"account_token_ownership_limit":1000}';
219 await expect(helper.methods222 await expect(collectionEvm.methods
220 .setLimits(collectionAddressWithBadPrefix, limits)223 .setLimits(limits)
221 .call()).to.be.rejectedWith(EXPECTED_ERROR);224 .call()).to.be.rejectedWith(EXPECTED_ERROR);
222 }225 }
223 });226 });
224227
225 itWeb3('(!negative test!) Check owner', async ({api, web3}) => {228 itWeb3('(!negative test!) Check owner', async ({api, web3}) => {
226 const owner = await createEthAccountWithBalance(api, web3);229 const owner = await createEthAccountWithBalance(api, web3);
227 const notOwner = await createEthAccount(web3);230 const notOwner = await createEthAccount(web3);
228 const helperFromOwner = collectionHelper(web3, owner);231 const collectionHelper = evmCollectionHelper(web3, owner);
229 const helperFromNotOwner = collectionHelper(web3, notOwner);
230 const result = await helperFromOwner.methods.create721Collection('A', 'A', 'A').send();232 const result = await collectionHelper.methods.create721Collection('A', 'A', 'A').send();
231 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);233 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
234 const contractEvmFromNotOwner = evmCollection(web3, notOwner, collectionIdAddress);
232 const EXPECTED_ERROR = 'NoPermission';235 const EXPECTED_ERROR = 'NoPermission';
233 {236 {
234 const sponsor = await createEthAccountWithBalance(api, web3);237 const sponsor = await createEthAccountWithBalance(api, web3);
235 await expect(helperFromNotOwner.methods238 await expect(contractEvmFromNotOwner.methods
236 .setSponsor(collectionIdAddress, sponsor)239 .setSponsor(sponsor)
237 .call()).to.be.rejectedWith(EXPECTED_ERROR);240 .call()).to.be.rejectedWith(EXPECTED_ERROR);
238 241
239 const sponsorHelper = collectionHelper(web3, sponsor);242 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
240 await expect(sponsorHelper.methods243 await expect(sponsorCollection.methods
241 .confirmSponsorship(collectionIdAddress)244 .confirmSponsorship()
242 .call()).to.be.rejectedWith('Caller is not set as sponsor');245 .call()).to.be.rejectedWith('Caller is not set as sponsor');
243 }246 }
244 {247 {
245 const limits = '{"account_token_ownership_limit":1000}';248 const limits = '{"account_token_ownership_limit":1000}';
246 await expect(helperFromNotOwner.methods249 await expect(contractEvmFromNotOwner.methods
247 .setLimits(collectionIdAddress, limits)250 .setLimits(limits)
248 .call()).to.be.rejectedWith(EXPECTED_ERROR);251 .call()).to.be.rejectedWith(EXPECTED_ERROR);
249 }252 }
250 });253 });
251254
252 itWeb3('(!negative test!) Set limits', async ({api, web3}) => {255 itWeb3('(!negative test!) Set limits', async ({api, web3}) => {
253 const owner = await createEthAccountWithBalance(api, web3);256 const owner = await createEthAccountWithBalance(api, web3);
254 const helper = collectionHelper(web3, owner);257 const collectionHelper = evmCollectionHelper(web3, owner);
255 const result = await helper.methods.create721Collection('Schema collection', 'A', 'A').send();258 const result = await collectionHelper.methods.create721Collection('Schema collection', 'A', 'A').send();
256 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);259 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
260 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
257 const badJson = '{accountTokenOwnershipLimit: 1000}';261 const badJson = '{accountTokenOwnershipLimit: 1000}';
258 await expect(helper.methods262 await expect(collectionEvm.methods
259 .setLimits(collectionIdAddress, badJson)263 .setLimits(badJson)
260 .call()).to.be.rejectedWith('Parse JSON error:');264 .call()).to.be.rejectedWith('Parse JSON error:');
261 });265 });
262});266});
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
29import privateKey from '../../substrate/privateKey';29import privateKey from '../../substrate/privateKey';
30import contractHelpersAbi from './contractHelpersAbi.json';30import contractHelpersAbi from './contractHelpersAbi.json';
31import collectionAbi from '../collectionAbi.json';31import collectionAbi from '../collectionAbi.json';
32import collectionHelperAbi from '../collectionHelperAbi.json';
32import getBalance from '../../substrate/get-balance';33import getBalance from '../../substrate/get-balance';
33import waitNewBlocks from '../../substrate/wait-new-blocks';34import waitNewBlocks from '../../substrate/wait-new-blocks';
3435
282 return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS});283 return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS});
283}284}
284285
285/** 286/**
286 * pallet evm_collection287 * evm collection helper
287 * @param web3 288 * @param web3
288 * @param caller - eth address289 * @param caller - eth address
289 * @returns 290 * @returns
290 */291 */
291export function collectionHelper(web3: Web3, caller: string) {292export function evmCollectionHelper(web3: Web3, caller: string) {
292 return new web3.eth.Contract(collectionAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS});293 return new web3.eth.Contract(collectionHelperAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS});
293}294}
295
296/**
297 * evm collection
298 * @param web3
299 * @param caller - eth address
300 * @returns
301 */
302export function evmCollection(web3: Web3, caller: string, collection: string) {
303 return new web3.eth.Contract(collectionAbi as any, collection, {from: caller, ...GAS_ARGS});
304}
294305
295/**306/**
296 * Execute ethereum method call using substrate account307 * Execute ethereum method call using substrate account
modifiedtests/src/interfaces/unique/types.tsdiffbeforeafterboth
6import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill } from '@polkadot/types/interfaces/runtime';6import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill } from '@polkadot/types/interfaces/runtime';
7import type { Event } from '@polkadot/types/interfaces/system';7import type { Event } from '@polkadot/types/interfaces/system';
8
9/** @name BTreeSet */
10export interface BTreeSet extends BTreeSet<Bytes> {}
118
12/** @name CumulusPalletDmpQueueCall */9/** @name CumulusPalletDmpQueueCall */
13export interface CumulusPalletDmpQueueCall extends Enum {10export interface CumulusPalletDmpQueueCall extends Enum {