difftreelog
CORE-337 Rewrite set limits
in: master
9 files changed
pallets/common/src/erc.rsdiffbeforeafterboth161617use evm_coder::{solidity_interface, types::*, execution::{Result, Error}};17use evm_coder::{solidity_interface, types::*, execution::{Result, Error}};18pub use pallet_evm::{PrecompileOutput, PrecompileResult, account::CrossAccountId};18pub use pallet_evm::{PrecompileOutput, PrecompileResult, account::CrossAccountId};19use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder};19use pallet_evm_coder_substrate::dispatch_to_evm;20use sp_core::{H160, U256};20use sp_core::{H160, U256};21use sp_std::vec::Vec;21use sp_std::vec::Vec;22use up_data_structs::Property;22use up_data_structs::{Property, SponsoringRateLimit};23use alloc::format;232424use crate::{Pallet, CollectionHandle, Config, CollectionProperties};25use crate::{Pallet, CollectionHandle, Config, CollectionProperties};252687 Ok(())88 Ok(())88 }89 }899090 fn set_limits(91 fn set_limit(91 &self,92 &mut self,92 caller: caller,93 caller: caller,93 limits_json: string,94 limit: string,95 value: string,94 ) -> Result<void> {96 ) -> Result<void> {95 // let mut collection = collection_from_address::<T>(self.contract_address(caller).unwrap(), self.1.gas_left())?;97 check_is_owner(caller, self)?;96 // check_is_owner(caller, &collection)?;98 let mut limits = self.limits.clone();979998 // let limits = serde_json_core::from_str(limits_json.as_ref())100 match limit.as_str() {99 // .map_err(|e| Error::Revert(format!("Parse JSON error: {}", e)))?;101 "accountTokenOwnershipLimit" => {100 // collection.limits = limits.0;102 limits.account_token_ownership_limit = parse_int(value)?;101 // collection.save().map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;103 },104 "sponsoredDataSize" => {105 limits.sponsored_data_size = parse_int(value)?;106 },107 "sponsoredDataRateLimit" => {108 limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(parse_int(value)?.unwrap()));109 },110 "tokenLimit" => {111 limits.token_limit = parse_int(value)?;112 },113 "sponsorTransferTimeout" => {114 limits.sponsor_transfer_timeout = parse_int(value)?;115 },116 "sponsorApproveTimeout" => {117 limits.sponsor_approve_timeout = parse_int(value)?;118 },119 "ownerCanTransfer" => {120 limits.owner_can_transfer = parse_bool(value)?;121 },122 "ownerCanDestroy" => {123 limits.owner_can_destroy = parse_bool(value)?;124 },125 "transfersEnabled" => {126 limits.transfers_enabled = parse_bool(value)?;127 },128 _ => return Err(Error::Revert(format!("Unknown limit \"{}\"", limit)))129 }130 self.limits = limits;131 save(self);102 Ok(())132 Ok(())103 }133 }104134107 }137 }108}138}109110fn collection_from_address<T: Config>(111 collection_address: address,112 gas_limit: u64113) -> Result<CollectionHandle<T>> {114 let collection_id = crate::eth::map_eth_to_id(&collection_address)115 .ok_or(Error::Revert("Contract is not an unique collection".into()))?;116 let recorder = <SubstrateRecorder<T>>::new(gas_limit);117 let collection =118 CollectionHandle::new_with_recorder(collection_id, recorder)119 .ok_or(Error::Revert("Create collection handle error".into()))?;120 Ok(collection)121}122139123fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {140fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {124 let caller = T::CrossAccountId::from_eth(caller);141 let caller = T::CrossAccountId::from_eth(caller);132 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());149 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());133}150}151152fn parse_int(value: string) -> Result<Option<u32>> {153 value.parse::<u32>()154 .map_err(|e| Error::Revert(format!("Int value \"{}\" parse error: {}", value, e)))155 .map(|value| Some(value))156}157158fn parse_bool(value: string) -> Result<Option<bool>> {159 value.parse::<bool>()160 .map_err(|e| Error::Revert(format!("Bool value \"{}\" parse error: {}", value, e)))161 .map(|value| Some(value))162}pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth51 event MintingFinished();51 event MintingFinished();52}52}5354// Selector: 38e33c6055contract Collection is Dummy, ERC165 {56 // Selector: setCollectionProperty(string,bytes) 2f073f6657 function setCollectionProperty(string memory key, bytes memory value)58 public59 {60 require(false, stub_error);61 key;62 value;63 dummy = 0;64 }6566 // Selector: deleteCollectionProperty(string) 7b7debce67 function deleteCollectionProperty(string memory key) public {68 require(false, stub_error);69 key;70 dummy = 0;71 }7273 // Throws error if key not found74 //75 // Selector: collectionProperty(string) cf24fd6d76 function collectionProperty(string memory key)77 public78 view79 returns (bytes memory)80 {81 require(false, stub_error);82 key;83 dummy;84 return hex"";85 }8687 // Selector: ethSetSponsor(address) 8f9af35688 function ethSetSponsor(address sponsor) public {89 require(false, stub_error);90 sponsor;91 dummy = 0;92 }9394 // Selector: ethConfirmSponsorship() a8580d1a95 function ethConfirmSponsorship() public {96 require(false, stub_error);97 dummy = 0;98 }99100 // Selector: setLimits(string) 72cb345d101 function setLimits(string memory limitsJson) public view {102 require(false, stub_error);103 limitsJson;104 dummy;105 }106107 // Selector: contractAddress() f6b4dfb4108 function contractAddress() public view returns (address) {109 require(false, stub_error);110 dummy;111 return 0x0000000000000000000000000000000000000000;112 }113}11453115// Selector: 4136937754// Selector: 41369377116contract TokenProperties is Dummy, ERC165 {55contract TokenProperties is Dummy, ERC165 {441 }380 }442}381}382383// Selector: f5652829384contract Collection is Dummy, ERC165 {385 // Selector: setCollectionProperty(string,bytes) 2f073f66386 function setCollectionProperty(string memory key, bytes memory value)387 public388 {389 require(false, stub_error);390 key;391 value;392 dummy = 0;393 }394395 // Selector: deleteCollectionProperty(string) 7b7debce396 function deleteCollectionProperty(string memory key) public {397 require(false, stub_error);398 key;399 dummy = 0;400 }401402 // Throws error if key not found403 //404 // Selector: collectionProperty(string) cf24fd6d405 function collectionProperty(string memory key)406 public407 view408 returns (bytes memory)409 {410 require(false, stub_error);411 key;412 dummy;413 return hex"";414 }415416 // Selector: ethSetSponsor(address) 8f9af356417 function ethSetSponsor(address sponsor) public {418 require(false, stub_error);419 sponsor;420 dummy = 0;421 }422423 // Selector: ethConfirmSponsorship() a8580d1a424 function ethConfirmSponsorship() public {425 require(false, stub_error);426 dummy = 0;427 }428429 // Selector: setLimit(string,string) bf4d2014430 function setLimit(string memory limit, string memory value) public {431 require(false, stub_error);432 limit;433 value;434 dummy = 0;435 }436437 // Selector: contractAddress() f6b4dfb4438 function contractAddress() public view returns (address) {439 require(false, stub_error);440 dummy;441 return 0x0000000000000000000000000000000000000000;442 }443}443444444contract UniqueNFT is445contract UniqueNFT is445 Dummy,446 Dummy,pallets/unique/src/eth/mod.rsdiffbeforeafterboth26 };26 };27 use frame_support::traits::Get;27 use frame_support::traits::Get;28 use sp_core::H160;28 use sp_core::H160;29 use pallet_common::{CollectionHandle, CollectionById};29 use pallet_common::CollectionById;30 30 31 use sp_std::vec::Vec;31 use sp_std::vec::Vec;32 use alloc::format;32 use alloc::format;primitives/data-structs/src/lib.rsdiffbeforeafterboth368#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]368#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]369#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]369#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]370pub struct CollectionLimits {370pub struct CollectionLimits {371 #[serde(alias = "accountTokenOwnershipLimit")]372 pub account_token_ownership_limit: Option<u32>,371 pub account_token_ownership_limit: Option<u32>,373 #[serde(alias = "sponsoredDataSize")]374 pub sponsored_data_size: Option<u32>,372 pub sponsored_data_size: Option<u32>,375373376 /// FIXME should we delete this or repurpose it?374 /// FIXME should we delete this or repurpose it?377 /// None - setVariableMetadata is not sponsored375 /// None - setVariableMetadata is not sponsored378 /// Some(v) - setVariableMetadata is sponsored376 /// Some(v) - setVariableMetadata is sponsored379 /// if there is v block between txs377 /// if there is v block between txs380 #[serde(alias = "sponsoredDataRateLimit")]381 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,378 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,382 #[serde(alias = "tokenLimit")]383 pub token_limit: Option<u32>,379 pub token_limit: Option<u32>,384380385 // Timeouts for item types in passed blocks381 // Timeouts for item types in passed blocks386 #[serde(alias = "sponsorTransferTimeout")]387 pub sponsor_transfer_timeout: Option<u32>,382 pub sponsor_transfer_timeout: Option<u32>,388 #[serde(alias = "sponsorApproveTimeout")]389 pub sponsor_approve_timeout: Option<u32>,383 pub sponsor_approve_timeout: Option<u32>,390 #[serde(alias = "ownerCanTransfer")]391 pub owner_can_transfer: Option<bool>,384 pub owner_can_transfer: Option<bool>,392 #[serde(alias = "ownerCanDestroy")]393 pub owner_can_destroy: Option<bool>,385 pub owner_can_destroy: Option<bool>,394 #[serde(alias = "transfersEnabled")]395 pub transfers_enabled: Option<bool>,386 pub transfers_enabled: Option<bool>,396}387}397388tests/src/eth/api/Collection.soldiffbeforeafterbothno changes
tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth42 event MintingFinished();42 event MintingFinished();43}43}4445// Selector: 38e33c6046interface Collection is Dummy, ERC165 {47 // Selector: setCollectionProperty(string,bytes) 2f073f6648 function setCollectionProperty(string memory key, bytes memory value)49 external;5051 // Selector: deleteCollectionProperty(string) 7b7debce52 function deleteCollectionProperty(string memory key) external;5354 // Throws error if key not found55 //56 // Selector: collectionProperty(string) cf24fd6d57 function collectionProperty(string memory key)58 external59 view60 returns (bytes memory);6162 // Selector: ethSetSponsor(address) 8f9af35663 function ethSetSponsor(address sponsor) external;6465 // Selector: ethConfirmSponsorship() a8580d1a66 function ethConfirmSponsorship() external;6768 // Selector: setLimits(string) 72cb345d69 function setLimits(string memory limitsJson) external view;7071 // Selector: contractAddress() f6b4dfb472 function contractAddress() external view returns (address);73}744475// Selector: 4136937745// Selector: 4136937776interface TokenProperties is Dummy, ERC165 {46interface TokenProperties is Dummy, ERC165 {243 returns (bool);213 returns (bool);244}214}215216// Selector: f5652829217interface Collection is Dummy, ERC165 {218 // Selector: setCollectionProperty(string,bytes) 2f073f66219 function setCollectionProperty(string memory key, bytes memory value)220 external;221222 // Selector: deleteCollectionProperty(string) 7b7debce223 function deleteCollectionProperty(string memory key) external;224225 // Throws error if key not found226 //227 // Selector: collectionProperty(string) cf24fd6d228 function collectionProperty(string memory key)229 external230 view231 returns (bytes memory);232233 // Selector: ethSetSponsor(address) 8f9af356234 function ethSetSponsor(address sponsor) external;235236 // Selector: ethConfirmSponsorship() a8580d1a237 function ethConfirmSponsorship() external;238239 // Selector: setLimit(string,string) bf4d2014240 function setLimit(string memory limit, string memory value) external;241242 // Selector: contractAddress() f6b4dfb4243 function contractAddress() external view returns (address);244}245245246interface UniqueNFT is246interface UniqueNFT is247 Dummy,247 Dummy,tests/src/eth/createCollection.test.tsdiffbeforeafterboth108 const limits = {108 const limits = {109 accountTokenOwnershipLimit: 1000,109 accountTokenOwnershipLimit: 1000,110 sponsoredDataSize: 1024,110 sponsoredDataSize: 1024,111 sponsoredDataRateLimit: {Blocks: 30},111 sponsoredDataRateLimit: 30,112 tokenLimit: 1000000,112 tokenLimit: 1000000,113 sponsorTransferTimeout: 6,113 sponsorTransferTimeout: 6,114 sponsorApproveTimeout: 6,114 sponsorApproveTimeout: 6,117 transfersEnabled: false,117 transfersEnabled: false,118 };118 };119119120 const limitsJson = JSON.stringify(limits, null, 1);121 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);120 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);122 await collectionEvm.methods.setLimits(limitsJson).send();121 await collectionEvm.methods.setLimit('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit.toString()).send();123 122 await collectionEvm.methods.setLimit('sponsoredDataSize', limits.sponsoredDataSize.toString()).send();123 await collectionEvm.methods.setLimit('sponsoredDataRateLimit', limits.sponsoredDataRateLimit.toString()).send();124 await collectionEvm.methods.setLimit('tokenLimit', limits.tokenLimit.toString()).send();125 await collectionEvm.methods.setLimit('sponsorTransferTimeout', limits.sponsorTransferTimeout.toString()).send();126 await collectionEvm.methods.setLimit('sponsorApproveTimeout', limits.sponsorApproveTimeout.toString()).send();127 await collectionEvm.methods.setLimit('ownerCanTransfer', limits.ownerCanTransfer.toString()).send();128 await collectionEvm.methods.setLimit('ownerCanDestroy', limits.ownerCanDestroy.toString()).send();129 await collectionEvm.methods.setLimit('transfersEnabled', limits.transfersEnabled.toString()).send();130 124 const collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;131 const collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;125 expect(collectionSub.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit);132 expect(collectionSub.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit);126 expect(collectionSub.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize);133 expect(collectionSub.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize);127 expect(collectionSub.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit.Blocks);134 expect(collectionSub.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit);128 expect(collectionSub.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit);135 expect(collectionSub.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit);129 expect(collectionSub.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout);136 expect(collectionSub.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout);130 expect(collectionSub.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout);137 expect(collectionSub.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout);172 // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);179 // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);173 });180 });181182 itWeb3('Collection address exist', async ({api, web3}) => {183 const owner = await createEthAccountWithBalance(api, web3);184 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';185 const collectionHelper = evmCollectionHelper(web3, owner);186 expect(await collectionHelper.methods187 .isCollectionExist(collectionAddressForNonexistentCollection).call())188 .to.be.false;189 190 const result = await collectionHelper.methods.create721Collection('Const collection', '5', '5').send();191 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);192 expect(await collectionHelper.methods193 .isCollectionExist(collectionIdAddress).call())194 .to.be.true;195 });174});196});175197176describe('(!negative tests!) Create collection from EVM', () => {198describe('(!negative tests!) Create collection from EVM', () => {220 .call()).to.be.rejectedWith('NotSufficientFounds');242 .call()).to.be.rejectedWith('NotSufficientFounds');221 });243 });222223 itWeb3('(!negative test!) Collection address (Create collection handle error)', async ({api, web3}) => {224 const owner = await createEthAccountWithBalance(api, web3);225 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';226 const collectionEvm = evmCollection(web3, owner, collectionAddressForNonexistentCollection);227 const EXPECTED_ERROR = 'Create collection handle error';228 {229 const sponsor = await createEthAccountWithBalance(api, web3);230 await expect(collectionEvm.methods231 .setSponsor(sponsor)232 .call()).to.be.rejectedWith(EXPECTED_ERROR);233 234 const sponsorCollection = evmCollection(web3, sponsor, collectionAddressForNonexistentCollection);235 await expect(sponsorCollection.methods236 .confirmSponsorship()237 .call()).to.be.rejectedWith(EXPECTED_ERROR);238 }239 {240 const limits = '{"account_token_ownership_limit":1000}';241 await expect(collectionEvm.methods242 .setLimits(limits)243 .call()).to.be.rejectedWith(EXPECTED_ERROR);244 }245 });246244247 itWeb3('(!negative test!) Check owner', async ({api, web3}) => {245 itWeb3('(!negative test!) Check owner', async ({api, web3}) => {248 const owner = await createEthAccountWithBalance(api, web3);246 const owner = await createEthAccountWithBalance(api, web3);255 {253 {256 const sponsor = await createEthAccountWithBalance(api, web3);254 const sponsor = await createEthAccountWithBalance(api, web3);257 await expect(contractEvmFromNotOwner.methods255 await expect(contractEvmFromNotOwner.methods258 .setSponsor(sponsor)256 .ethSetSponsor(sponsor)259 .call()).to.be.rejectedWith(EXPECTED_ERROR);257 .call()).to.be.rejectedWith(EXPECTED_ERROR);260 258 261 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);259 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);262 await expect(sponsorCollection.methods260 await expect(sponsorCollection.methods263 .confirmSponsorship()261 .ethConfirmSponsorship()264 .call()).to.be.rejectedWith('Caller is not set as sponsor');262 .call()).to.be.rejectedWith('Caller is not set as sponsor');265 }263 }266 {264 {267 const limits = '{"account_token_ownership_limit":1000}';268 await expect(contractEvmFromNotOwner.methods265 await expect(contractEvmFromNotOwner.methods269 .setLimits(limits)266 .setLimit('account_token_ownership_limit', '1000')270 .call()).to.be.rejectedWith(EXPECTED_ERROR);267 .call()).to.be.rejectedWith(EXPECTED_ERROR);271 }268 }272 });269 });277 const result = await collectionHelper.methods.create721Collection('Schema collection', 'A', 'A').send();274 const result = await collectionHelper.methods.create721Collection('Schema collection', 'A', 'A').send();278 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);275 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);279 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);276 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);277 await expect(collectionEvm.methods278 .setLimit('badLimit', 'true')280 const badJson = '{accountTokenOwnershipLimit: 1000}';279 .call()).to.be.rejectedWith('Unknown limit "badLimit"');281 await expect(collectionEvm.methods280 await expect(collectionEvm.methods282 .setLimits(badJson)281 .setLimit('sponsoredDataSize', 'badValue')283 .call()).to.be.rejectedWith('Parse JSON error:');282 .call()).to.be.rejectedWith('Int value "badValue" parse error:');283 await expect(collectionEvm.methods284 .setLimit('ownerCanTransfer', 'badValue')285 .call()).to.be.rejectedWith('Bool value "badValue" parse error:');284 });286 });285});287});tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth325 },325 },326 {326 {327 "inputs": [327 "inputs": [328 { "internalType": "string", "name": "limitsJson", "type": "string" }328 { "internalType": "string", "name": "limit", "type": "string" },329 { "internalType": "string", "name": "value", "type": "string" }329 ],330 ],330 "name": "setLimits",331 "name": "setLimit",331 "outputs": [],332 "outputs": [],332 "stateMutability": "view",333 "stateMutability": "nonpayable",333 "type": "function"334 "type": "function"334 },335 },335 {336 {