--- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -27,6 +27,8 @@ use derivative::Derivative; use scale_info::TypeInfo; +mod migration; + pub const MAX_DECIMAL_POINTS: DecimalPoints = 30; pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000; pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000; @@ -319,7 +321,7 @@ /// None - setVariableMetadata is not sponsored /// Some(v) - setVariableMetadata is sponsored /// if there is v block between txs - pub sponsored_data_rate_limit: Option<(Option,)>, + pub sponsored_data_rate_limit: Option, pub token_limit: Option, // Timeouts for item types in passed blocks @@ -366,13 +368,23 @@ self.transfers_enabled.unwrap_or(true) } pub fn sponsored_data_rate_limit(&self) -> Option { - self.sponsored_data_rate_limit - .unwrap_or((None,)) - .0 - .map(|v| v.min(MAX_SPONSOR_TIMEOUT)) + match self + .sponsored_data_rate_limit + .unwrap_or(SponsoringRateLimit::SponsoringDisabled) + { + SponsoringRateLimit::SponsoringDisabled => None, + SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)), + } } } +#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub enum SponsoringRateLimit { + SponsoringDisabled, + Blocks(u32), +} + /// BoundedVec doesn't supports serde #[cfg(feature = "serde1")] mod bounded_serde { --- /dev/null +++ b/primitives/data-structs/src/migration.rs @@ -0,0 +1,24 @@ +/// Storage migration is not required for this change, as SponsoringRateLimit has same encoding as Option +#[test] +fn sponsoring_rate_limit_has_same_encoding_as_option_u32() { + use crate::SponsoringRateLimit; + use codec::Encode; + + fn limit_to_option(limit: SponsoringRateLimit) -> Option { + match limit { + SponsoringRateLimit::SponsoringDisabled => None, + SponsoringRateLimit::Blocks(v) => Some(v), + } + } + + fn test_to_option(limit: SponsoringRateLimit) { + let encoded = limit.encode(); + let option = limit_to_option(limit); + let encoded_option = option.encode(); + + assert_eq!(encoded, encoded_option); + } + + test_to_option(SponsoringRateLimit::SponsoringDisabled); + test_to_option(SponsoringRateLimit::Blocks(10)); +} --- a/tests/src/interfaces/augment-types.ts +++ b/tests/src/interfaces/augment-types.ts @@ -1,7 +1,7 @@ // Auto-generated via `yarn polkadot-types-from-defs`, do not edit /* eslint-disable */ -import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonAccountBasicCrossAccountIdRepr, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1AbridgedHrmpChannel, PolkadotPrimitivesV1PersistedValidationData, PolkadotPrimitivesV1UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpTrieStorageProof, SpVersionRuntimeVersion, UniqueRuntimeRuntime, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateNftData, UpDataStructsCreateReFungibleData, UpDataStructsMetaUpdatePermission, UpDataStructsSchemaVersion, UpDataStructsSponsorshipState, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './unique'; +import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonAccountBasicCrossAccountIdRepr, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1AbridgedHrmpChannel, PolkadotPrimitivesV1PersistedValidationData, PolkadotPrimitivesV1UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpTrieStorageProof, SpVersionRuntimeVersion, UniqueRuntimeRuntime, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateNftData, UpDataStructsCreateReFungibleData, UpDataStructsMetaUpdatePermission, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './unique'; import type { Data, StorageKey } from '@polkadot/types'; import type { BitVec, Bool, Bytes, I128, I16, I256, I32, I64, I8, Json, Null, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec'; import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets'; @@ -1167,6 +1167,7 @@ UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData; UpDataStructsMetaUpdatePermission: UpDataStructsMetaUpdatePermission; UpDataStructsSchemaVersion: UpDataStructsSchemaVersion; + UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit; UpDataStructsSponsorshipState: UpDataStructsSponsorshipState; UpgradeGoAhead: UpgradeGoAhead; UpgradeRestriction: UpgradeRestriction; --- a/tests/src/interfaces/types-lookup.ts +++ b/tests/src/interfaces/types-lookup.ts @@ -1513,11 +1513,19 @@ readonly type: 'ImageURL' | 'Unique'; } + /** @name UpDataStructsSponsoringRateLimit */ + export interface UpDataStructsSponsoringRateLimit extends Enum { + readonly isSponsoringDisabled: boolean; + readonly isBlocks: boolean; + readonly asBlocks: u32; + readonly type: 'SponsoringDisabled' | 'Blocks'; + } + /** @name UpDataStructsCollectionLimits (163) */ export interface UpDataStructsCollectionLimits extends Struct { readonly accountTokenOwnershipLimit: Option; readonly sponsoredDataSize: Option; - readonly sponsoredDataRateLimit: Option>; + readonly sponsoredDataRateLimit: Option; readonly tokenLimit: Option; readonly sponsorTransferTimeout: Option; readonly sponsorApproveTimeout: Option; --- a/tests/src/interfaces/unique/types.ts +++ b/tests/src/interfaces/unique/types.ts @@ -1720,7 +1720,7 @@ export interface UpDataStructsCollectionLimits extends Struct { readonly accountTokenOwnershipLimit: Option; readonly sponsoredDataSize: Option; - readonly sponsoredDataRateLimit: Option>; + readonly sponsoredDataRateLimit: Option; readonly tokenLimit: Option; readonly sponsorTransferTimeout: Option; readonly sponsorApproveTimeout: Option; @@ -1805,6 +1805,13 @@ readonly type: 'ImageURL' | 'Unique'; } +/** @name UpDataStructsSponsoringRateLimit */ +export interface UpDataStructsSponsoringRateLimit extends Enum { + readonly isSponsoringDisabled: boolean; + readonly isBlocks: boolean; + readonly asBlocks: u32; +} + /** @name UpDataStructsSponsorshipState */ export interface UpDataStructsSponsorshipState extends Enum { readonly isDisabled: boolean; --- a/tests/src/setVariableMetadataSponsoringRateLimit.test.ts +++ b/tests/src/setVariableMetadataSponsoringRateLimit.test.ts @@ -4,6 +4,7 @@ // import {IKeyringPair} from '@polkadot/types/types'; +import {expect} from 'chai'; import privateKey from './substrate/privateKey'; import usingApi from './substrate/substrate-api'; import { @@ -11,6 +12,7 @@ createCollectionExpectSuccess, createItemExpectSuccess, findUnusedAddress, + getDetailedCollectionInfo, setCollectionLimitsExpectSuccess, setCollectionSponsorExpectSuccess, setVariableMetaDataExpectFailure, @@ -33,7 +35,7 @@ await setCollectionSponsorExpectSuccess(collectionId, alice.address); await confirmSponsorshipExpectSuccess(collectionId); await setCollectionLimitsExpectSuccess(alice, collectionId, { - sponsoredDataRateLimit: 0, + sponsoredDataRateLimit: {Blocks: 0}, }); const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); @@ -46,7 +48,7 @@ await setCollectionSponsorExpectSuccess(collectionId, alice.address); await confirmSponsorshipExpectSuccess(collectionId); await setCollectionLimitsExpectSuccess(alice, collectionId, { - sponsoredDataRateLimit: 10, + sponsoredDataRateLimit: {Blocks: 10}, }); const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); @@ -59,7 +61,7 @@ await setCollectionSponsorExpectSuccess(collectionId, alice.address); await confirmSponsorshipExpectSuccess(collectionId); await setCollectionLimitsExpectSuccess(alice, collectionId, { - sponsoredDataRateLimit: 0, + sponsoredDataRateLimit: {Blocks: 0}, sponsoredDataSize: 1, }); const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); @@ -77,4 +79,32 @@ await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1]); }); + it('sponsoring of data is disabled by default', async () => { + await usingApi(async api => { + const collectionId = await createCollectionExpectSuccess(); + + const collection = (await getDetailedCollectionInfo(api, collectionId))!; + // limit is none = default is used + expect(collection?.limits.sponsoredDataRateLimit.isNone); + }); + }); + + it('sponsoring can be disabled explicitly', async () => { + await usingApi(async api => { + const collectionId = await createCollectionExpectSuccess(); + + await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsoredDataRateLimit: {Blocks: 6}}); + { + const collection = (await getDetailedCollectionInfo(api, collectionId))!; + expect(collection?.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.equal(6); + } + + await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsoredDataRateLimit: 'SponsoringDisabled'}); + { + const collection = (await getDetailedCollectionInfo(api, collectionId))!; + // disabled sponsoring = default value + expect(collection?.limits.sponsoredDataRateLimit.unwrap().isNone).to.true; + } + }); + }); });